[runtime] Cleanup the debugger header files. (#4459)
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12  */
13
14 #include <config.h>
15 #include <mono/utils/mono-compiler.h>
16
17 #ifndef DISABLE_JIT
18
19 #include <signal.h>
20
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24
25 #include <math.h>
26 #include <string.h>
27 #include <ctype.h>
28
29 #ifdef HAVE_SYS_TIME_H
30 #include <sys/time.h>
31 #endif
32
33 #ifdef HAVE_ALLOCA_H
34 #include <alloca.h>
35 #endif
36
37 #include <mono/utils/memcheck.h>
38 #include "mini.h"
39 #include <mono/metadata/abi-details.h>
40 #include <mono/metadata/assembly.h>
41 #include <mono/metadata/attrdefs.h>
42 #include <mono/metadata/loader.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/class.h>
45 #include <mono/metadata/object.h>
46 #include <mono/metadata/exception.h>
47 #include <mono/metadata/opcodes.h>
48 #include <mono/metadata/mono-endian.h>
49 #include <mono/metadata/tokentype.h>
50 #include <mono/metadata/tabledefs.h>
51 #include <mono/metadata/marshal.h>
52 #include <mono/metadata/debug-helpers.h>
53 #include <mono/metadata/debug-internals.h>
54 #include <mono/metadata/gc-internals.h>
55 #include <mono/metadata/security-manager.h>
56 #include <mono/metadata/threads-types.h>
57 #include <mono/metadata/security-core-clr.h>
58 #include <mono/metadata/profiler-private.h>
59 #include <mono/metadata/profiler.h>
60 #include <mono/metadata/monitor.h>
61 #include <mono/utils/mono-memory-model.h>
62 #include <mono/utils/mono-error-internals.h>
63 #include <mono/metadata/mono-basic-block.h>
64 #include <mono/metadata/reflection-internals.h>
65 #include <mono/utils/mono-threads-coop.h>
66
67 #include "trace.h"
68
69 #include "ir-emit.h"
70
71 #include "jit-icalls.h"
72 #include "jit.h"
73 #include "debugger-agent.h"
74 #include "seq-points.h"
75 #include "aot-compiler.h"
76 #include "mini-llvm.h"
77
78 #define BRANCH_COST 10
79 #define INLINE_LENGTH_LIMIT 20
80
81 /* These have 'cfg' as an implicit argument */
82 #define INLINE_FAILURE(msg) do {                                                                        \
83         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
84                 inline_failure (cfg, msg);                                                                              \
85                 goto exception_exit;                                                                                    \
86         } \
87         } while (0)
88 #define CHECK_CFG_EXCEPTION do {\
89                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
90                         goto exception_exit;                                            \
91         } while (0)
92 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
93                 field_access_failure ((cfg), (method), (field));                        \
94                 goto exception_exit;    \
95         } while (0)
96 #define GENERIC_SHARING_FAILURE(opcode) do {            \
97                 if (cfg->gshared) {                                                                     \
98                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
99                         goto exception_exit;    \
100                 }                       \
101         } while (0)
102 #define GSHAREDVT_FAILURE(opcode) do {          \
103         if (cfg->gsharedvt) {                                                                                           \
104                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
105                 goto exception_exit;                                                                                    \
106         }                                                                                                                                       \
107         } while (0)
108 #define OUT_OF_MEMORY_FAILURE do {      \
109                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
110                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
111                 goto exception_exit;    \
112         } while (0)
113 #define DISABLE_AOT(cfg) do { \
114                 if ((cfg)->verbose_level >= 2)                                            \
115                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
116                 (cfg)->disable_aot = TRUE;                                                        \
117         } while (0)
118 #define LOAD_ERROR do { \
119                 break_on_unverified ();                                                         \
120                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
121                 goto exception_exit;                                                                    \
122         } while (0)
123
124 #define TYPE_LOAD_ERROR(klass) do { \
125                 cfg->exception_ptr = klass; \
126                 LOAD_ERROR;                                     \
127         } while (0)
128
129 #define CHECK_CFG_ERROR do {\
130                 if (!mono_error_ok (&cfg->error)) { \
131                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
132                         goto mono_error_exit; \
133                 } \
134         } while (0)
135
136 /* Determine whenever 'ins' represents a load of the 'this' argument */
137 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
138
139 static int ldind_to_load_membase (int opcode);
140 static int stind_to_store_membase (int opcode);
141
142 int mono_op_to_op_imm (int opcode);
143 int mono_op_to_op_imm_noemul (int opcode);
144
145 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
146
147 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
148                                                   guchar *ip, guint real_offset, gboolean inline_always);
149 static MonoInst*
150 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
151
152 inline static MonoInst*
153 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg);
154
155 /* helper methods signatures */
156 static MonoMethodSignature *helper_sig_domain_get;
157 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
158 static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline;
159 static MonoMethodSignature *helper_sig_jit_thread_attach;
160 static MonoMethodSignature *helper_sig_get_tls_tramp;
161 static MonoMethodSignature *helper_sig_set_tls_tramp;
162
163 /* type loading helpers */
164 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, "System.Runtime.CompilerServices", "RuntimeHelpers")
165 static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, "System.Diagnostics", "DebuggableAttribute")
166
167 /*
168  * Instruction metadata
169  */
170 #ifdef MINI_OP
171 #undef MINI_OP
172 #endif
173 #ifdef MINI_OP3
174 #undef MINI_OP3
175 #endif
176 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
177 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
178 #define NONE ' '
179 #define IREG 'i'
180 #define FREG 'f'
181 #define VREG 'v'
182 #define XREG 'x'
183 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
184 #define LREG IREG
185 #else
186 #define LREG 'l'
187 #endif
188 /* keep in sync with the enum in mini.h */
189 const char
190 ins_info[] = {
191 #include "mini-ops.h"
192 };
193 #undef MINI_OP
194 #undef MINI_OP3
195
196 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
197 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
198 /* 
199  * This should contain the index of the last sreg + 1. This is not the same
200  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
201  */
202 const gint8 ins_sreg_counts[] = {
203 #include "mini-ops.h"
204 };
205 #undef MINI_OP
206 #undef MINI_OP3
207
208 guint32
209 mono_alloc_ireg (MonoCompile *cfg)
210 {
211         return alloc_ireg (cfg);
212 }
213
214 guint32
215 mono_alloc_lreg (MonoCompile *cfg)
216 {
217         return alloc_lreg (cfg);
218 }
219
220 guint32
221 mono_alloc_freg (MonoCompile *cfg)
222 {
223         return alloc_freg (cfg);
224 }
225
226 guint32
227 mono_alloc_preg (MonoCompile *cfg)
228 {
229         return alloc_preg (cfg);
230 }
231
232 guint32
233 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
234 {
235         return alloc_dreg (cfg, stack_type);
236 }
237
238 /*
239  * mono_alloc_ireg_ref:
240  *
241  *   Allocate an IREG, and mark it as holding a GC ref.
242  */
243 guint32
244 mono_alloc_ireg_ref (MonoCompile *cfg)
245 {
246         return alloc_ireg_ref (cfg);
247 }
248
249 /*
250  * mono_alloc_ireg_mp:
251  *
252  *   Allocate an IREG, and mark it as holding a managed pointer.
253  */
254 guint32
255 mono_alloc_ireg_mp (MonoCompile *cfg)
256 {
257         return alloc_ireg_mp (cfg);
258 }
259
260 /*
261  * mono_alloc_ireg_copy:
262  *
263  *   Allocate an IREG with the same GC type as VREG.
264  */
265 guint32
266 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
267 {
268         if (vreg_is_ref (cfg, vreg))
269                 return alloc_ireg_ref (cfg);
270         else if (vreg_is_mp (cfg, vreg))
271                 return alloc_ireg_mp (cfg);
272         else
273                 return alloc_ireg (cfg);
274 }
275
276 guint
277 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
278 {
279         if (type->byref)
280                 return OP_MOVE;
281
282         type = mini_get_underlying_type (type);
283 handle_enum:
284         switch (type->type) {
285         case MONO_TYPE_I1:
286         case MONO_TYPE_U1:
287                 return OP_MOVE;
288         case MONO_TYPE_I2:
289         case MONO_TYPE_U2:
290                 return OP_MOVE;
291         case MONO_TYPE_I4:
292         case MONO_TYPE_U4:
293                 return OP_MOVE;
294         case MONO_TYPE_I:
295         case MONO_TYPE_U:
296         case MONO_TYPE_PTR:
297         case MONO_TYPE_FNPTR:
298                 return OP_MOVE;
299         case MONO_TYPE_CLASS:
300         case MONO_TYPE_STRING:
301         case MONO_TYPE_OBJECT:
302         case MONO_TYPE_SZARRAY:
303         case MONO_TYPE_ARRAY:    
304                 return OP_MOVE;
305         case MONO_TYPE_I8:
306         case MONO_TYPE_U8:
307 #if SIZEOF_REGISTER == 8
308                 return OP_MOVE;
309 #else
310                 return OP_LMOVE;
311 #endif
312         case MONO_TYPE_R4:
313                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
314         case MONO_TYPE_R8:
315                 return OP_FMOVE;
316         case MONO_TYPE_VALUETYPE:
317                 if (type->data.klass->enumtype) {
318                         type = mono_class_enum_basetype (type->data.klass);
319                         goto handle_enum;
320                 }
321                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
322                         return OP_XMOVE;
323                 return OP_VMOVE;
324         case MONO_TYPE_TYPEDBYREF:
325                 return OP_VMOVE;
326         case MONO_TYPE_GENERICINST:
327                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
328                         return OP_XMOVE;
329                 type = &type->data.generic_class->container_class->byval_arg;
330                 goto handle_enum;
331         case MONO_TYPE_VAR:
332         case MONO_TYPE_MVAR:
333                 g_assert (cfg->gshared);
334                 if (mini_type_var_is_vt (type))
335                         return OP_VMOVE;
336                 else
337                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
338         default:
339                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
340         }
341         return -1;
342 }
343
344 void
345 mono_print_bb (MonoBasicBlock *bb, const char *msg)
346 {
347         int i;
348         MonoInst *tree;
349         GString *str = g_string_new ("");
350
351         g_string_append_printf (str, "%s %d: [IN: ", msg, bb->block_num);
352         for (i = 0; i < bb->in_count; ++i)
353                 g_string_append_printf (str, " BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
354         g_string_append_printf (str, ", OUT: ");
355         for (i = 0; i < bb->out_count; ++i)
356                 g_string_append_printf (str, " BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
357         g_string_append_printf (str, " ]\n");
358
359         g_print ("%s", str->str);
360         g_string_free (str, TRUE);
361
362         for (tree = bb->code; tree; tree = tree->next)
363                 mono_print_ins_index (-1, tree);
364 }
365
366 void
367 mono_create_helper_signatures (void)
368 {
369         helper_sig_domain_get = mono_create_icall_signature ("ptr");
370         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
371         helper_sig_llvmonly_imt_trampoline = mono_create_icall_signature ("ptr ptr ptr");
372         helper_sig_jit_thread_attach = mono_create_icall_signature ("ptr ptr");
373         helper_sig_get_tls_tramp = mono_create_icall_signature ("ptr");
374         helper_sig_set_tls_tramp = mono_create_icall_signature ("void ptr");
375 }
376
377 static MONO_NEVER_INLINE void
378 break_on_unverified (void)
379 {
380         if (mini_get_debug_options ()->break_on_unverified)
381                 G_BREAKPOINT ();
382 }
383
384 static MONO_NEVER_INLINE void
385 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
386 {
387         char *method_fname = mono_method_full_name (method, TRUE);
388         char *field_fname = mono_field_full_name (field);
389         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
390         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
391         g_free (method_fname);
392         g_free (field_fname);
393 }
394
395 static MONO_NEVER_INLINE void
396 inline_failure (MonoCompile *cfg, const char *msg)
397 {
398         if (cfg->verbose_level >= 2)
399                 printf ("inline failed: %s\n", msg);
400         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
401 }
402
403 static MONO_NEVER_INLINE void
404 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
405 {
406         if (cfg->verbose_level > 2)                                                                                     \
407                 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);
408         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
409 }
410
411 static MONO_NEVER_INLINE void
412 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
413 {
414         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);
415         if (cfg->verbose_level >= 2)
416                 printf ("%s\n", cfg->exception_message);
417         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
418 }
419
420 /*
421  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
422  * foo<T> (int i) { ldarg.0; box T; }
423  */
424 #define UNVERIFIED do { \
425         if (cfg->gsharedvt) { \
426                 if (cfg->verbose_level > 2)                                                                     \
427                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
428                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
429                 goto exception_exit;                                                                                    \
430         }                                                                                                                                       \
431         break_on_unverified ();                                                                                         \
432         goto unverified;                                                                                                        \
433 } while (0)
434
435 #define GET_BBLOCK(cfg,tblock,ip) do {  \
436                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
437                 if (!(tblock)) {        \
438                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
439             NEW_BBLOCK (cfg, (tblock)); \
440                         (tblock)->cil_code = (ip);      \
441                         ADD_BBLOCK (cfg, (tblock));     \
442                 } \
443         } while (0)
444
445 #if defined(TARGET_X86) || defined(TARGET_AMD64)
446 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
447                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
448                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
449                 (dest)->sreg1 = (sr1); \
450                 (dest)->sreg2 = (sr2); \
451                 (dest)->inst_imm = (imm); \
452                 (dest)->backend.shift_amount = (shift); \
453                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
454         } while (0)
455 #endif
456
457 /* Emit conversions so both operands of a binary opcode are of the same type */
458 static void
459 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
460 {
461         MonoInst *arg1 = *arg1_ref;
462         MonoInst *arg2 = *arg2_ref;
463
464         if (cfg->r4fp &&
465                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
466                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
467                 MonoInst *conv;
468
469                 /* Mixing r4/r8 is allowed by the spec */
470                 if (arg1->type == STACK_R4) {
471                         int dreg = alloc_freg (cfg);
472
473                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
474                         conv->type = STACK_R8;
475                         ins->sreg1 = dreg;
476                         *arg1_ref = conv;
477                 }
478                 if (arg2->type == STACK_R4) {
479                         int dreg = alloc_freg (cfg);
480
481                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
482                         conv->type = STACK_R8;
483                         ins->sreg2 = dreg;
484                         *arg2_ref = conv;
485                 }
486         }
487
488 #if SIZEOF_REGISTER == 8
489         /* FIXME: Need to add many more cases */
490         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
491                 MonoInst *widen;
492
493                 int dr = alloc_preg (cfg);
494                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
495                 (ins)->sreg2 = widen->dreg;
496         }
497 #endif
498 }
499
500 #define ADD_BINOP(op) do {      \
501                 MONO_INST_NEW (cfg, ins, (op)); \
502                 sp -= 2;        \
503                 ins->sreg1 = sp [0]->dreg;      \
504                 ins->sreg2 = sp [1]->dreg;      \
505                 type_from_op (cfg, ins, sp [0], sp [1]);        \
506                 CHECK_TYPE (ins);       \
507                 /* Have to insert a widening op */               \
508         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
509         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
510         MONO_ADD_INS ((cfg)->cbb, (ins)); \
511         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
512         } while (0)
513
514 #define ADD_UNOP(op) do {       \
515                 MONO_INST_NEW (cfg, ins, (op)); \
516                 sp--;   \
517                 ins->sreg1 = sp [0]->dreg;      \
518                 type_from_op (cfg, ins, sp [0], NULL);  \
519                 CHECK_TYPE (ins);       \
520         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
521         MONO_ADD_INS ((cfg)->cbb, (ins)); \
522                 *sp++ = mono_decompose_opcode (cfg, ins);       \
523         } while (0)
524
525 #define ADD_BINCOND(next_block) do {    \
526                 MonoInst *cmp;  \
527                 sp -= 2; \
528                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
529                 cmp->sreg1 = sp [0]->dreg;      \
530                 cmp->sreg2 = sp [1]->dreg;      \
531                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
532                 CHECK_TYPE (cmp);       \
533                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
534                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
535                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
536                 GET_BBLOCK (cfg, tblock, target);               \
537                 link_bblock (cfg, cfg->cbb, tblock);    \
538                 ins->inst_true_bb = tblock;     \
539                 if ((next_block)) {     \
540                         link_bblock (cfg, cfg->cbb, (next_block));      \
541                         ins->inst_false_bb = (next_block);      \
542                         start_new_bblock = 1;   \
543                 } else {        \
544                         GET_BBLOCK (cfg, tblock, ip);           \
545                         link_bblock (cfg, cfg->cbb, tblock);    \
546                         ins->inst_false_bb = tblock;    \
547                         start_new_bblock = 2;   \
548                 }       \
549                 if (sp != stack_start) {                                                                        \
550                     handle_stack_args (cfg, stack_start, sp - stack_start); \
551                         CHECK_UNVERIFIABLE (cfg); \
552                 } \
553         MONO_ADD_INS (cfg->cbb, cmp); \
554                 MONO_ADD_INS (cfg->cbb, ins);   \
555         } while (0)
556
557 /* *
558  * link_bblock: Links two basic blocks
559  *
560  * links two basic blocks in the control flow graph, the 'from'
561  * argument is the starting block and the 'to' argument is the block
562  * the control flow ends to after 'from'.
563  */
564 static void
565 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
566 {
567         MonoBasicBlock **newa;
568         int i, found;
569
570 #if 0
571         if (from->cil_code) {
572                 if (to->cil_code)
573                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
574                 else
575                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
576         } else {
577                 if (to->cil_code)
578                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
579                 else
580                         printf ("edge from entry to exit\n");
581         }
582 #endif
583
584         found = FALSE;
585         for (i = 0; i < from->out_count; ++i) {
586                 if (to == from->out_bb [i]) {
587                         found = TRUE;
588                         break;
589                 }
590         }
591         if (!found) {
592                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
593                 for (i = 0; i < from->out_count; ++i) {
594                         newa [i] = from->out_bb [i];
595                 }
596                 newa [i] = to;
597                 from->out_count++;
598                 from->out_bb = newa;
599         }
600
601         found = FALSE;
602         for (i = 0; i < to->in_count; ++i) {
603                 if (from == to->in_bb [i]) {
604                         found = TRUE;
605                         break;
606                 }
607         }
608         if (!found) {
609                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
610                 for (i = 0; i < to->in_count; ++i) {
611                         newa [i] = to->in_bb [i];
612                 }
613                 newa [i] = from;
614                 to->in_count++;
615                 to->in_bb = newa;
616         }
617 }
618
619 void
620 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
621 {
622         link_bblock (cfg, from, to);
623 }
624
625 /**
626  * mono_find_block_region:
627  *
628  *   We mark each basic block with a region ID. We use that to avoid BB
629  *   optimizations when blocks are in different regions.
630  *
631  * Returns:
632  *   A region token that encodes where this region is, and information
633  *   about the clause owner for this block.
634  *
635  *   The region encodes the try/catch/filter clause that owns this block
636  *   as well as the type.  -1 is a special value that represents a block
637  *   that is in none of try/catch/filter.
638  */
639 static int
640 mono_find_block_region (MonoCompile *cfg, int offset)
641 {
642         MonoMethodHeader *header = cfg->header;
643         MonoExceptionClause *clause;
644         int i;
645
646         for (i = 0; i < header->num_clauses; ++i) {
647                 clause = &header->clauses [i];
648                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
649                     (offset < (clause->handler_offset)))
650                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
651                            
652                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
653                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
654                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
655                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
656                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
657                         else
658                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
659                 }
660         }
661         for (i = 0; i < header->num_clauses; ++i) {
662                 clause = &header->clauses [i];
663
664                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
665                         return ((i + 1) << 8) | clause->flags;
666         }
667
668         return -1;
669 }
670
671 static gboolean
672 ip_in_finally_clause (MonoCompile *cfg, int offset)
673 {
674         MonoMethodHeader *header = cfg->header;
675         MonoExceptionClause *clause;
676         int i;
677
678         for (i = 0; i < header->num_clauses; ++i) {
679                 clause = &header->clauses [i];
680                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
681                         continue;
682
683                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
684                         return TRUE;
685         }
686         return FALSE;
687 }
688
689 static GList*
690 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
691 {
692         MonoMethodHeader *header = cfg->header;
693         MonoExceptionClause *clause;
694         int i;
695         GList *res = NULL;
696
697         for (i = 0; i < header->num_clauses; ++i) {
698                 clause = &header->clauses [i];
699                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
700                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
701                         if (clause->flags == type)
702                                 res = g_list_append (res, clause);
703                 }
704         }
705         return res;
706 }
707
708 static void
709 mono_create_spvar_for_region (MonoCompile *cfg, int region)
710 {
711         MonoInst *var;
712
713         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
714         if (var)
715                 return;
716
717         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
718         /* prevent it from being register allocated */
719         var->flags |= MONO_INST_VOLATILE;
720
721         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
722 }
723
724 MonoInst *
725 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
726 {
727         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
728 }
729
730 static MonoInst*
731 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
732 {
733         MonoInst *var;
734
735         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
736         if (var)
737                 return var;
738
739         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
740         /* prevent it from being register allocated */
741         var->flags |= MONO_INST_VOLATILE;
742
743         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
744
745         return var;
746 }
747
748 /*
749  * Returns the type used in the eval stack when @type is loaded.
750  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
751  */
752 void
753 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
754 {
755         MonoClass *klass;
756
757         type = mini_get_underlying_type (type);
758         inst->klass = klass = mono_class_from_mono_type (type);
759         if (type->byref) {
760                 inst->type = STACK_MP;
761                 return;
762         }
763
764 handle_enum:
765         switch (type->type) {
766         case MONO_TYPE_VOID:
767                 inst->type = STACK_INV;
768                 return;
769         case MONO_TYPE_I1:
770         case MONO_TYPE_U1:
771         case MONO_TYPE_I2:
772         case MONO_TYPE_U2:
773         case MONO_TYPE_I4:
774         case MONO_TYPE_U4:
775                 inst->type = STACK_I4;
776                 return;
777         case MONO_TYPE_I:
778         case MONO_TYPE_U:
779         case MONO_TYPE_PTR:
780         case MONO_TYPE_FNPTR:
781                 inst->type = STACK_PTR;
782                 return;
783         case MONO_TYPE_CLASS:
784         case MONO_TYPE_STRING:
785         case MONO_TYPE_OBJECT:
786         case MONO_TYPE_SZARRAY:
787         case MONO_TYPE_ARRAY:    
788                 inst->type = STACK_OBJ;
789                 return;
790         case MONO_TYPE_I8:
791         case MONO_TYPE_U8:
792                 inst->type = STACK_I8;
793                 return;
794         case MONO_TYPE_R4:
795                 inst->type = cfg->r4_stack_type;
796                 break;
797         case MONO_TYPE_R8:
798                 inst->type = STACK_R8;
799                 return;
800         case MONO_TYPE_VALUETYPE:
801                 if (type->data.klass->enumtype) {
802                         type = mono_class_enum_basetype (type->data.klass);
803                         goto handle_enum;
804                 } else {
805                         inst->klass = klass;
806                         inst->type = STACK_VTYPE;
807                         return;
808                 }
809         case MONO_TYPE_TYPEDBYREF:
810                 inst->klass = mono_defaults.typed_reference_class;
811                 inst->type = STACK_VTYPE;
812                 return;
813         case MONO_TYPE_GENERICINST:
814                 type = &type->data.generic_class->container_class->byval_arg;
815                 goto handle_enum;
816         case MONO_TYPE_VAR:
817         case MONO_TYPE_MVAR:
818                 g_assert (cfg->gshared);
819                 if (mini_is_gsharedvt_type (type)) {
820                         g_assert (cfg->gsharedvt);
821                         inst->type = STACK_VTYPE;
822                 } else {
823                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
824                 }
825                 return;
826         default:
827                 g_error ("unknown type 0x%02x in eval stack type", type->type);
828         }
829 }
830
831 /*
832  * The following tables are used to quickly validate the IL code in type_from_op ().
833  */
834 static const char
835 bin_num_table [STACK_MAX] [STACK_MAX] = {
836         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
837         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
838         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
839         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
840         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
841         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
842         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
843         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
844         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
845 };
846
847 static const char 
848 neg_table [] = {
849         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
850 };
851
852 /* reduce the size of this table */
853 static const char
854 bin_int_table [STACK_MAX] [STACK_MAX] = {
855         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
856         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
857         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
858         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
859         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
860         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
861         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
862         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
863 };
864
865 static const char
866 bin_comp_table [STACK_MAX] [STACK_MAX] = {
867 /*      Inv i  L  p  F  &  O  vt r4 */
868         {0},
869         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
870         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
871         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
872         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
873         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
874         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
875         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
876         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
877 };
878
879 /* reduce the size of this table */
880 static const char
881 shift_table [STACK_MAX] [STACK_MAX] = {
882         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
883         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
884         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
885         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
886         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
887         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
888         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
889         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
890 };
891
892 /*
893  * Tables to map from the non-specific opcode to the matching
894  * type-specific opcode.
895  */
896 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
897 static const guint16
898 binops_op_map [STACK_MAX] = {
899         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
900 };
901
902 /* handles from CEE_NEG to CEE_CONV_U8 */
903 static const guint16
904 unops_op_map [STACK_MAX] = {
905         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
906 };
907
908 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
909 static const guint16
910 ovfops_op_map [STACK_MAX] = {
911         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
912 };
913
914 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
915 static const guint16
916 ovf2ops_op_map [STACK_MAX] = {
917         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
918 };
919
920 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
921 static const guint16
922 ovf3ops_op_map [STACK_MAX] = {
923         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
924 };
925
926 /* handles from CEE_BEQ to CEE_BLT_UN */
927 static const guint16
928 beqops_op_map [STACK_MAX] = {
929         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
930 };
931
932 /* handles from CEE_CEQ to CEE_CLT_UN */
933 static const guint16
934 ceqops_op_map [STACK_MAX] = {
935         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
936 };
937
938 /*
939  * Sets ins->type (the type on the eval stack) according to the
940  * type of the opcode and the arguments to it.
941  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
942  *
943  * FIXME: this function sets ins->type unconditionally in some cases, but
944  * it should set it to invalid for some types (a conv.x on an object)
945  */
946 static void
947 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
948 {
949         switch (ins->opcode) {
950         /* binops */
951         case CEE_ADD:
952         case CEE_SUB:
953         case CEE_MUL:
954         case CEE_DIV:
955         case CEE_REM:
956                 /* FIXME: check unverifiable args for STACK_MP */
957                 ins->type = bin_num_table [src1->type] [src2->type];
958                 ins->opcode += binops_op_map [ins->type];
959                 break;
960         case CEE_DIV_UN:
961         case CEE_REM_UN:
962         case CEE_AND:
963         case CEE_OR:
964         case CEE_XOR:
965                 ins->type = bin_int_table [src1->type] [src2->type];
966                 ins->opcode += binops_op_map [ins->type];
967                 break;
968         case CEE_SHL:
969         case CEE_SHR:
970         case CEE_SHR_UN:
971                 ins->type = shift_table [src1->type] [src2->type];
972                 ins->opcode += binops_op_map [ins->type];
973                 break;
974         case OP_COMPARE:
975         case OP_LCOMPARE:
976         case OP_ICOMPARE:
977                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
978                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
979                         ins->opcode = OP_LCOMPARE;
980                 else if (src1->type == STACK_R4)
981                         ins->opcode = OP_RCOMPARE;
982                 else if (src1->type == STACK_R8)
983                         ins->opcode = OP_FCOMPARE;
984                 else
985                         ins->opcode = OP_ICOMPARE;
986                 break;
987         case OP_ICOMPARE_IMM:
988                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
989                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
990                         ins->opcode = OP_LCOMPARE_IMM;          
991                 break;
992         case CEE_BEQ:
993         case CEE_BGE:
994         case CEE_BGT:
995         case CEE_BLE:
996         case CEE_BLT:
997         case CEE_BNE_UN:
998         case CEE_BGE_UN:
999         case CEE_BGT_UN:
1000         case CEE_BLE_UN:
1001         case CEE_BLT_UN:
1002                 ins->opcode += beqops_op_map [src1->type];
1003                 break;
1004         case OP_CEQ:
1005                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
1006                 ins->opcode += ceqops_op_map [src1->type];
1007                 break;
1008         case OP_CGT:
1009         case OP_CGT_UN:
1010         case OP_CLT:
1011         case OP_CLT_UN:
1012                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
1013                 ins->opcode += ceqops_op_map [src1->type];
1014                 break;
1015         /* unops */
1016         case CEE_NEG:
1017                 ins->type = neg_table [src1->type];
1018                 ins->opcode += unops_op_map [ins->type];
1019                 break;
1020         case CEE_NOT:
1021                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1022                         ins->type = src1->type;
1023                 else
1024                         ins->type = STACK_INV;
1025                 ins->opcode += unops_op_map [ins->type];
1026                 break;
1027         case CEE_CONV_I1:
1028         case CEE_CONV_I2:
1029         case CEE_CONV_I4:
1030         case CEE_CONV_U4:
1031                 ins->type = STACK_I4;
1032                 ins->opcode += unops_op_map [src1->type];
1033                 break;
1034         case CEE_CONV_R_UN:
1035                 ins->type = STACK_R8;
1036                 switch (src1->type) {
1037                 case STACK_I4:
1038                 case STACK_PTR:
1039                         ins->opcode = OP_ICONV_TO_R_UN;
1040                         break;
1041                 case STACK_I8:
1042                         ins->opcode = OP_LCONV_TO_R_UN; 
1043                         break;
1044                 }
1045                 break;
1046         case CEE_CONV_OVF_I1:
1047         case CEE_CONV_OVF_U1:
1048         case CEE_CONV_OVF_I2:
1049         case CEE_CONV_OVF_U2:
1050         case CEE_CONV_OVF_I4:
1051         case CEE_CONV_OVF_U4:
1052                 ins->type = STACK_I4;
1053                 ins->opcode += ovf3ops_op_map [src1->type];
1054                 break;
1055         case CEE_CONV_OVF_I_UN:
1056         case CEE_CONV_OVF_U_UN:
1057                 ins->type = STACK_PTR;
1058                 ins->opcode += ovf2ops_op_map [src1->type];
1059                 break;
1060         case CEE_CONV_OVF_I1_UN:
1061         case CEE_CONV_OVF_I2_UN:
1062         case CEE_CONV_OVF_I4_UN:
1063         case CEE_CONV_OVF_U1_UN:
1064         case CEE_CONV_OVF_U2_UN:
1065         case CEE_CONV_OVF_U4_UN:
1066                 ins->type = STACK_I4;
1067                 ins->opcode += ovf2ops_op_map [src1->type];
1068                 break;
1069         case CEE_CONV_U:
1070                 ins->type = STACK_PTR;
1071                 switch (src1->type) {
1072                 case STACK_I4:
1073                         ins->opcode = OP_ICONV_TO_U;
1074                         break;
1075                 case STACK_PTR:
1076                 case STACK_MP:
1077 #if SIZEOF_VOID_P == 8
1078                         ins->opcode = OP_LCONV_TO_U;
1079 #else
1080                         ins->opcode = OP_MOVE;
1081 #endif
1082                         break;
1083                 case STACK_I8:
1084                         ins->opcode = OP_LCONV_TO_U;
1085                         break;
1086                 case STACK_R8:
1087                         ins->opcode = OP_FCONV_TO_U;
1088                         break;
1089                 }
1090                 break;
1091         case CEE_CONV_I8:
1092         case CEE_CONV_U8:
1093                 ins->type = STACK_I8;
1094                 ins->opcode += unops_op_map [src1->type];
1095                 break;
1096         case CEE_CONV_OVF_I8:
1097         case CEE_CONV_OVF_U8:
1098                 ins->type = STACK_I8;
1099                 ins->opcode += ovf3ops_op_map [src1->type];
1100                 break;
1101         case CEE_CONV_OVF_U8_UN:
1102         case CEE_CONV_OVF_I8_UN:
1103                 ins->type = STACK_I8;
1104                 ins->opcode += ovf2ops_op_map [src1->type];
1105                 break;
1106         case CEE_CONV_R4:
1107                 ins->type = cfg->r4_stack_type;
1108                 ins->opcode += unops_op_map [src1->type];
1109                 break;
1110         case CEE_CONV_R8:
1111                 ins->type = STACK_R8;
1112                 ins->opcode += unops_op_map [src1->type];
1113                 break;
1114         case OP_CKFINITE:
1115                 ins->type = STACK_R8;           
1116                 break;
1117         case CEE_CONV_U2:
1118         case CEE_CONV_U1:
1119                 ins->type = STACK_I4;
1120                 ins->opcode += ovfops_op_map [src1->type];
1121                 break;
1122         case CEE_CONV_I:
1123         case CEE_CONV_OVF_I:
1124         case CEE_CONV_OVF_U:
1125                 ins->type = STACK_PTR;
1126                 ins->opcode += ovfops_op_map [src1->type];
1127                 break;
1128         case CEE_ADD_OVF:
1129         case CEE_ADD_OVF_UN:
1130         case CEE_MUL_OVF:
1131         case CEE_MUL_OVF_UN:
1132         case CEE_SUB_OVF:
1133         case CEE_SUB_OVF_UN:
1134                 ins->type = bin_num_table [src1->type] [src2->type];
1135                 ins->opcode += ovfops_op_map [src1->type];
1136                 if (ins->type == STACK_R8)
1137                         ins->type = STACK_INV;
1138                 break;
1139         case OP_LOAD_MEMBASE:
1140                 ins->type = STACK_PTR;
1141                 break;
1142         case OP_LOADI1_MEMBASE:
1143         case OP_LOADU1_MEMBASE:
1144         case OP_LOADI2_MEMBASE:
1145         case OP_LOADU2_MEMBASE:
1146         case OP_LOADI4_MEMBASE:
1147         case OP_LOADU4_MEMBASE:
1148                 ins->type = STACK_PTR;
1149                 break;
1150         case OP_LOADI8_MEMBASE:
1151                 ins->type = STACK_I8;
1152                 break;
1153         case OP_LOADR4_MEMBASE:
1154                 ins->type = cfg->r4_stack_type;
1155                 break;
1156         case OP_LOADR8_MEMBASE:
1157                 ins->type = STACK_R8;
1158                 break;
1159         default:
1160                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1161                 break;
1162         }
1163
1164         if (ins->type == STACK_MP)
1165                 ins->klass = mono_defaults.object_class;
1166 }
1167
1168 static const char 
1169 ldind_type [] = {
1170         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1171 };
1172
1173 #if 0
1174
1175 static const char
1176 param_table [STACK_MAX] [STACK_MAX] = {
1177         {0},
1178 };
1179
1180 static int
1181 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1182 {
1183         int i;
1184
1185         if (sig->hasthis) {
1186                 switch (args->type) {
1187                 case STACK_I4:
1188                 case STACK_I8:
1189                 case STACK_R8:
1190                 case STACK_VTYPE:
1191                 case STACK_INV:
1192                         return 0;
1193                 }
1194                 args++;
1195         }
1196         for (i = 0; i < sig->param_count; ++i) {
1197                 switch (args [i].type) {
1198                 case STACK_INV:
1199                         return 0;
1200                 case STACK_MP:
1201                         if (!sig->params [i]->byref)
1202                                 return 0;
1203                         continue;
1204                 case STACK_OBJ:
1205                         if (sig->params [i]->byref)
1206                                 return 0;
1207                         switch (sig->params [i]->type) {
1208                         case MONO_TYPE_CLASS:
1209                         case MONO_TYPE_STRING:
1210                         case MONO_TYPE_OBJECT:
1211                         case MONO_TYPE_SZARRAY:
1212                         case MONO_TYPE_ARRAY:
1213                                 break;
1214                         default:
1215                                 return 0;
1216                         }
1217                         continue;
1218                 case STACK_R8:
1219                         if (sig->params [i]->byref)
1220                                 return 0;
1221                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1222                                 return 0;
1223                         continue;
1224                 case STACK_PTR:
1225                 case STACK_I4:
1226                 case STACK_I8:
1227                 case STACK_VTYPE:
1228                         break;
1229                 }
1230                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1231                         return 0;*/
1232         }
1233         return 1;
1234 }
1235 #endif
1236
1237 /*
1238  * When we need a pointer to the current domain many times in a method, we
1239  * call mono_domain_get() once and we store the result in a local variable.
1240  * This function returns the variable that represents the MonoDomain*.
1241  */
1242 inline static MonoInst *
1243 mono_get_domainvar (MonoCompile *cfg)
1244 {
1245         if (!cfg->domainvar)
1246                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1247         return cfg->domainvar;
1248 }
1249
1250 /*
1251  * The got_var contains the address of the Global Offset Table when AOT 
1252  * compiling.
1253  */
1254 MonoInst *
1255 mono_get_got_var (MonoCompile *cfg)
1256 {
1257         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1258                 return NULL;
1259         if (!cfg->got_var) {
1260                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1261         }
1262         return cfg->got_var;
1263 }
1264
1265 static MonoInst *
1266 mono_get_vtable_var (MonoCompile *cfg)
1267 {
1268         g_assert (cfg->gshared);
1269
1270         if (!cfg->rgctx_var) {
1271                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1272                 /* force the var to be stack allocated */
1273                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1274         }
1275
1276         return cfg->rgctx_var;
1277 }
1278
1279 static MonoType*
1280 type_from_stack_type (MonoInst *ins) {
1281         switch (ins->type) {
1282         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1283         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1284         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1285         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1286         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1287         case STACK_MP:
1288                 return &ins->klass->this_arg;
1289         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1290         case STACK_VTYPE: return &ins->klass->byval_arg;
1291         default:
1292                 g_error ("stack type %d to monotype not handled\n", ins->type);
1293         }
1294         return NULL;
1295 }
1296
1297 static G_GNUC_UNUSED int
1298 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1299 {
1300         t = mono_type_get_underlying_type (t);
1301         switch (t->type) {
1302         case MONO_TYPE_I1:
1303         case MONO_TYPE_U1:
1304         case MONO_TYPE_I2:
1305         case MONO_TYPE_U2:
1306         case MONO_TYPE_I4:
1307         case MONO_TYPE_U4:
1308                 return STACK_I4;
1309         case MONO_TYPE_I:
1310         case MONO_TYPE_U:
1311         case MONO_TYPE_PTR:
1312         case MONO_TYPE_FNPTR:
1313                 return STACK_PTR;
1314         case MONO_TYPE_CLASS:
1315         case MONO_TYPE_STRING:
1316         case MONO_TYPE_OBJECT:
1317         case MONO_TYPE_SZARRAY:
1318         case MONO_TYPE_ARRAY:    
1319                 return STACK_OBJ;
1320         case MONO_TYPE_I8:
1321         case MONO_TYPE_U8:
1322                 return STACK_I8;
1323         case MONO_TYPE_R4:
1324                 return cfg->r4_stack_type;
1325         case MONO_TYPE_R8:
1326                 return STACK_R8;
1327         case MONO_TYPE_VALUETYPE:
1328         case MONO_TYPE_TYPEDBYREF:
1329                 return STACK_VTYPE;
1330         case MONO_TYPE_GENERICINST:
1331                 if (mono_type_generic_inst_is_valuetype (t))
1332                         return STACK_VTYPE;
1333                 else
1334                         return STACK_OBJ;
1335                 break;
1336         default:
1337                 g_assert_not_reached ();
1338         }
1339
1340         return -1;
1341 }
1342
1343 static MonoClass*
1344 array_access_to_klass (int opcode)
1345 {
1346         switch (opcode) {
1347         case CEE_LDELEM_U1:
1348                 return mono_defaults.byte_class;
1349         case CEE_LDELEM_U2:
1350                 return mono_defaults.uint16_class;
1351         case CEE_LDELEM_I:
1352         case CEE_STELEM_I:
1353                 return mono_defaults.int_class;
1354         case CEE_LDELEM_I1:
1355         case CEE_STELEM_I1:
1356                 return mono_defaults.sbyte_class;
1357         case CEE_LDELEM_I2:
1358         case CEE_STELEM_I2:
1359                 return mono_defaults.int16_class;
1360         case CEE_LDELEM_I4:
1361         case CEE_STELEM_I4:
1362                 return mono_defaults.int32_class;
1363         case CEE_LDELEM_U4:
1364                 return mono_defaults.uint32_class;
1365         case CEE_LDELEM_I8:
1366         case CEE_STELEM_I8:
1367                 return mono_defaults.int64_class;
1368         case CEE_LDELEM_R4:
1369         case CEE_STELEM_R4:
1370                 return mono_defaults.single_class;
1371         case CEE_LDELEM_R8:
1372         case CEE_STELEM_R8:
1373                 return mono_defaults.double_class;
1374         case CEE_LDELEM_REF:
1375         case CEE_STELEM_REF:
1376                 return mono_defaults.object_class;
1377         default:
1378                 g_assert_not_reached ();
1379         }
1380         return NULL;
1381 }
1382
1383 /*
1384  * We try to share variables when possible
1385  */
1386 static MonoInst *
1387 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1388 {
1389         MonoInst *res;
1390         int pos, vnum;
1391
1392         /* inlining can result in deeper stacks */ 
1393         if (slot >= cfg->header->max_stack)
1394                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1395
1396         pos = ins->type - 1 + slot * STACK_MAX;
1397
1398         switch (ins->type) {
1399         case STACK_I4:
1400         case STACK_I8:
1401         case STACK_R8:
1402         case STACK_PTR:
1403         case STACK_MP:
1404         case STACK_OBJ:
1405                 if ((vnum = cfg->intvars [pos]))
1406                         return cfg->varinfo [vnum];
1407                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1408                 cfg->intvars [pos] = res->inst_c0;
1409                 break;
1410         default:
1411                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1412         }
1413         return res;
1414 }
1415
1416 static void
1417 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1418 {
1419         /* 
1420          * Don't use this if a generic_context is set, since that means AOT can't
1421          * look up the method using just the image+token.
1422          * table == 0 means this is a reference made from a wrapper.
1423          */
1424         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1425                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1426                 jump_info_token->image = image;
1427                 jump_info_token->token = token;
1428                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1429         }
1430 }
1431
1432 /*
1433  * This function is called to handle items that are left on the evaluation stack
1434  * at basic block boundaries. What happens is that we save the values to local variables
1435  * and we reload them later when first entering the target basic block (with the
1436  * handle_loaded_temps () function).
1437  * A single joint point will use the same variables (stored in the array bb->out_stack or
1438  * bb->in_stack, if the basic block is before or after the joint point).
1439  *
1440  * This function needs to be called _before_ emitting the last instruction of
1441  * the bb (i.e. before emitting a branch).
1442  * If the stack merge fails at a join point, cfg->unverifiable is set.
1443  */
1444 static void
1445 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1446 {
1447         int i, bindex;
1448         MonoBasicBlock *bb = cfg->cbb;
1449         MonoBasicBlock *outb;
1450         MonoInst *inst, **locals;
1451         gboolean found;
1452
1453         if (!count)
1454                 return;
1455         if (cfg->verbose_level > 3)
1456                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1457         if (!bb->out_scount) {
1458                 bb->out_scount = count;
1459                 //printf ("bblock %d has out:", bb->block_num);
1460                 found = FALSE;
1461                 for (i = 0; i < bb->out_count; ++i) {
1462                         outb = bb->out_bb [i];
1463                         /* exception handlers are linked, but they should not be considered for stack args */
1464                         if (outb->flags & BB_EXCEPTION_HANDLER)
1465                                 continue;
1466                         //printf (" %d", outb->block_num);
1467                         if (outb->in_stack) {
1468                                 found = TRUE;
1469                                 bb->out_stack = outb->in_stack;
1470                                 break;
1471                         }
1472                 }
1473                 //printf ("\n");
1474                 if (!found) {
1475                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1476                         for (i = 0; i < count; ++i) {
1477                                 /* 
1478                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1479                                  * stack slot and if they are of the same type.
1480                                  * This won't cause conflicts since if 'local' is used to 
1481                                  * store one of the values in the in_stack of a bblock, then
1482                                  * the same variable will be used for the same outgoing stack 
1483                                  * slot as well. 
1484                                  * This doesn't work when inlining methods, since the bblocks
1485                                  * in the inlined methods do not inherit their in_stack from
1486                                  * the bblock they are inlined to. See bug #58863 for an
1487                                  * example.
1488                                  */
1489                                 if (cfg->inlined_method)
1490                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1491                                 else
1492                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1493                         }
1494                 }
1495         }
1496
1497         for (i = 0; i < bb->out_count; ++i) {
1498                 outb = bb->out_bb [i];
1499                 /* exception handlers are linked, but they should not be considered for stack args */
1500                 if (outb->flags & BB_EXCEPTION_HANDLER)
1501                         continue;
1502                 if (outb->in_scount) {
1503                         if (outb->in_scount != bb->out_scount) {
1504                                 cfg->unverifiable = TRUE;
1505                                 return;
1506                         }
1507                         continue; /* check they are the same locals */
1508                 }
1509                 outb->in_scount = count;
1510                 outb->in_stack = bb->out_stack;
1511         }
1512
1513         locals = bb->out_stack;
1514         cfg->cbb = bb;
1515         for (i = 0; i < count; ++i) {
1516                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1517                 inst->cil_code = sp [i]->cil_code;
1518                 sp [i] = locals [i];
1519                 if (cfg->verbose_level > 3)
1520                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1521         }
1522
1523         /*
1524          * It is possible that the out bblocks already have in_stack assigned, and
1525          * the in_stacks differ. In this case, we will store to all the different 
1526          * in_stacks.
1527          */
1528
1529         found = TRUE;
1530         bindex = 0;
1531         while (found) {
1532                 /* Find a bblock which has a different in_stack */
1533                 found = FALSE;
1534                 while (bindex < bb->out_count) {
1535                         outb = bb->out_bb [bindex];
1536                         /* exception handlers are linked, but they should not be considered for stack args */
1537                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1538                                 bindex++;
1539                                 continue;
1540                         }
1541                         if (outb->in_stack != locals) {
1542                                 for (i = 0; i < count; ++i) {
1543                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1544                                         inst->cil_code = sp [i]->cil_code;
1545                                         sp [i] = locals [i];
1546                                         if (cfg->verbose_level > 3)
1547                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1548                                 }
1549                                 locals = outb->in_stack;
1550                                 found = TRUE;
1551                                 break;
1552                         }
1553                         bindex ++;
1554                 }
1555         }
1556 }
1557
1558 static MonoInst*
1559 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1560 {
1561         MonoInst *ins;
1562
1563         if (cfg->compile_aot) {
1564                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1565         } else {
1566                 MonoJumpInfo ji;
1567                 gpointer target;
1568                 MonoError error;
1569
1570                 ji.type = patch_type;
1571                 ji.data.target = data;
1572                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1573                 mono_error_assert_ok (&error);
1574
1575                 EMIT_NEW_PCONST (cfg, ins, target);
1576         }
1577         return ins;
1578 }
1579
1580 MonoInst*
1581 mini_emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1582 {
1583         return emit_runtime_constant (cfg, patch_type, data);
1584 }
1585
1586 static void 
1587 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1588 {
1589         int val_reg;
1590
1591         g_assert (val == 0);
1592
1593         if (align == 0)
1594                 align = 4;
1595
1596         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1597                 switch (size) {
1598                 case 1:
1599                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1600                         return;
1601                 case 2:
1602                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1603                         return;
1604                 case 4:
1605                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1606                         return;
1607 #if SIZEOF_REGISTER == 8
1608                 case 8:
1609                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1610                         return;
1611 #endif
1612                 }
1613         }
1614
1615         val_reg = alloc_preg (cfg);
1616
1617         if (SIZEOF_REGISTER == 8)
1618                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1619         else
1620                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1621
1622         if (align < 4) {
1623                 /* This could be optimized further if neccesary */
1624                 while (size >= 1) {
1625                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1626                         offset += 1;
1627                         size -= 1;
1628                 }
1629                 return;
1630         }       
1631
1632         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1633                 if (offset % 8) {
1634                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1635                         offset += 4;
1636                         size -= 4;
1637                 }
1638                 while (size >= 8) {
1639                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1640                         offset += 8;
1641                         size -= 8;
1642                 }
1643         }       
1644
1645         while (size >= 4) {
1646                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1647                 offset += 4;
1648                 size -= 4;
1649         }
1650         while (size >= 2) {
1651                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1652                 offset += 2;
1653                 size -= 2;
1654         }
1655         while (size >= 1) {
1656                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1657                 offset += 1;
1658                 size -= 1;
1659         }
1660 }
1661
1662 void 
1663 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1664 {
1665         int cur_reg;
1666
1667         if (align == 0)
1668                 align = 4;
1669
1670         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1671         g_assert (size < 10000);
1672
1673         if (align < 4) {
1674                 /* This could be optimized further if neccesary */
1675                 while (size >= 1) {
1676                         cur_reg = alloc_preg (cfg);
1677                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1678                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1679                         doffset += 1;
1680                         soffset += 1;
1681                         size -= 1;
1682                 }
1683         }
1684
1685         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1686                 while (size >= 8) {
1687                         cur_reg = alloc_preg (cfg);
1688                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1689                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1690                         doffset += 8;
1691                         soffset += 8;
1692                         size -= 8;
1693                 }
1694         }       
1695
1696         while (size >= 4) {
1697                 cur_reg = alloc_preg (cfg);
1698                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1699                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1700                 doffset += 4;
1701                 soffset += 4;
1702                 size -= 4;
1703         }
1704         while (size >= 2) {
1705                 cur_reg = alloc_preg (cfg);
1706                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1707                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1708                 doffset += 2;
1709                 soffset += 2;
1710                 size -= 2;
1711         }
1712         while (size >= 1) {
1713                 cur_reg = alloc_preg (cfg);
1714                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1715                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1716                 doffset += 1;
1717                 soffset += 1;
1718                 size -= 1;
1719         }
1720 }
1721
1722 static MonoInst*
1723 mono_create_fast_tls_getter (MonoCompile *cfg, MonoTlsKey key)
1724 {
1725         int tls_offset = mono_tls_get_tls_offset (key);
1726
1727         if (cfg->compile_aot)
1728                 return NULL;
1729
1730         if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
1731                 MonoInst *ins;
1732                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
1733                 ins->dreg = mono_alloc_preg (cfg);
1734                 ins->inst_offset = tls_offset;
1735                 return ins;
1736         }
1737         return NULL;
1738 }
1739
1740 static MonoInst*
1741 mono_create_fast_tls_setter (MonoCompile *cfg, MonoInst* value, MonoTlsKey key)
1742 {
1743         int tls_offset = mono_tls_get_tls_offset (key);
1744
1745         if (cfg->compile_aot)
1746                 return NULL;
1747
1748         if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
1749                 MonoInst *ins;
1750                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1751                 ins->sreg1 = value->dreg;
1752                 ins->inst_offset = tls_offset;
1753                 return ins;
1754         }
1755         return NULL;
1756 }
1757
1758
1759 MonoInst*
1760 mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key)
1761 {
1762         MonoInst *fast_tls = NULL;
1763
1764         if (!mini_get_debug_options ()->use_fallback_tls)
1765                 fast_tls = mono_create_fast_tls_getter (cfg, key);
1766
1767         if (fast_tls) {
1768                 MONO_ADD_INS (cfg->cbb, fast_tls);
1769                 return fast_tls;
1770         }
1771
1772         if (cfg->compile_aot) {
1773                 MonoInst *addr;
1774                 /*
1775                  * tls getters are critical pieces of code and we don't want to resolve them
1776                  * through the standard plt/tramp mechanism since we might expose ourselves
1777                  * to crashes and infinite recursions.
1778                  */
1779                 EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GET_TLS_TRAMP, (void*)key);
1780                 return mono_emit_calli (cfg, helper_sig_get_tls_tramp, NULL, addr, NULL, NULL);
1781         } else {
1782                 gpointer getter = mono_tls_get_tls_getter (key, FALSE);
1783                 return mono_emit_jit_icall (cfg, getter, NULL);
1784         }
1785 }
1786
1787 static MonoInst*
1788 mono_create_tls_set (MonoCompile *cfg, MonoInst *value, MonoTlsKey key)
1789 {
1790         MonoInst *fast_tls = NULL;
1791
1792         if (!mini_get_debug_options ()->use_fallback_tls)
1793                 fast_tls = mono_create_fast_tls_setter (cfg, value, key);
1794
1795         if (fast_tls) {
1796                 MONO_ADD_INS (cfg->cbb, fast_tls);
1797                 return fast_tls;
1798         }
1799
1800         if (cfg->compile_aot) {
1801                 MonoInst *addr;
1802                 EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_SET_TLS_TRAMP, (void*)key);
1803                 return mono_emit_calli (cfg, helper_sig_set_tls_tramp, &value, addr, NULL, NULL);
1804         } else {
1805                 gpointer setter = mono_tls_get_tls_setter (key, FALSE);
1806                 return mono_emit_jit_icall (cfg, setter, &value);
1807         }
1808 }
1809
1810 /*
1811  * emit_push_lmf:
1812  *
1813  *   Emit IR to push the current LMF onto the LMF stack.
1814  */
1815 static void
1816 emit_push_lmf (MonoCompile *cfg)
1817 {
1818         /*
1819          * Emit IR to push the LMF:
1820          * lmf_addr = <lmf_addr from tls>
1821          * lmf->lmf_addr = lmf_addr
1822          * lmf->prev_lmf = *lmf_addr
1823          * *lmf_addr = lmf
1824          */
1825         MonoInst *ins, *lmf_ins;
1826
1827         if (!cfg->lmf_ir)
1828                 return;
1829
1830         if (cfg->lmf_ir_mono_lmf) {
1831                 MonoInst *lmf_vara_ins, *lmf_ins;
1832                 /* Load current lmf */
1833                 lmf_ins = mono_create_tls_get (cfg, TLS_KEY_LMF);
1834                 g_assert (lmf_ins);
1835                 EMIT_NEW_VARLOADA (cfg, lmf_vara_ins, cfg->lmf_var, NULL);
1836                 /* Save previous_lmf */
1837                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_vara_ins->dreg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1838                 /* Set new LMF */
1839                 mono_create_tls_set (cfg, lmf_vara_ins, TLS_KEY_LMF);
1840         } else {
1841                 int lmf_reg, prev_lmf_reg;
1842                 /*
1843                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1844                  */
1845                 if (!cfg->lmf_addr_var)
1846                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1847
1848 #ifdef HOST_WIN32
1849                 ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
1850                 g_assert (ins);
1851                 int jit_tls_dreg = ins->dreg;
1852
1853                 lmf_reg = alloc_preg (cfg);
1854                 EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
1855 #else
1856                 lmf_ins = mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR);
1857                 g_assert (lmf_ins);
1858 #endif
1859                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
1860
1861                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1862                 lmf_reg = ins->dreg;
1863
1864                 prev_lmf_reg = alloc_preg (cfg);
1865                 /* Save previous_lmf */
1866                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
1867                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
1868                 /* Set new lmf */
1869                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
1870         }
1871 }
1872
1873 /*
1874  * emit_pop_lmf:
1875  *
1876  *   Emit IR to pop the current LMF from the LMF stack.
1877  */
1878 static void
1879 emit_pop_lmf (MonoCompile *cfg)
1880 {
1881         int lmf_reg, lmf_addr_reg;
1882         MonoInst *ins;
1883
1884         if (!cfg->lmf_ir)
1885                 return;
1886
1887         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1888         lmf_reg = ins->dreg;
1889
1890         if (cfg->lmf_ir_mono_lmf) {
1891                 /* Load previous_lmf */
1892                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, alloc_preg (cfg), lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1893                 /* Set new LMF */
1894                 mono_create_tls_set (cfg, ins, TLS_KEY_LMF);
1895         } else {
1896                 int prev_lmf_reg;
1897                 /*
1898                  * Emit IR to pop the LMF:
1899                  * *(lmf->lmf_addr) = lmf->prev_lmf
1900                  */
1901                 /* This could be called before emit_push_lmf () */
1902                 if (!cfg->lmf_addr_var)
1903                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1904                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
1905
1906                 prev_lmf_reg = alloc_preg (cfg);
1907                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1908                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
1909         }
1910 }
1911
1912 static void
1913 emit_instrumentation_call (MonoCompile *cfg, void *func)
1914 {
1915         MonoInst *iargs [1];
1916
1917         /*
1918          * Avoid instrumenting inlined methods since it can
1919          * distort profiling results.
1920          */
1921         if (cfg->method != cfg->current_method)
1922                 return;
1923
1924         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
1925                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
1926                 mono_emit_jit_icall (cfg, func, iargs);
1927         }
1928 }
1929
1930 static int
1931 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
1932 {
1933 handle_enum:
1934         type = mini_get_underlying_type (type);
1935         switch (type->type) {
1936         case MONO_TYPE_VOID:
1937                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
1938         case MONO_TYPE_I1:
1939         case MONO_TYPE_U1:
1940         case MONO_TYPE_I2:
1941         case MONO_TYPE_U2:
1942         case MONO_TYPE_I4:
1943         case MONO_TYPE_U4:
1944                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1945         case MONO_TYPE_I:
1946         case MONO_TYPE_U:
1947         case MONO_TYPE_PTR:
1948         case MONO_TYPE_FNPTR:
1949                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1950         case MONO_TYPE_CLASS:
1951         case MONO_TYPE_STRING:
1952         case MONO_TYPE_OBJECT:
1953         case MONO_TYPE_SZARRAY:
1954         case MONO_TYPE_ARRAY:    
1955                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1956         case MONO_TYPE_I8:
1957         case MONO_TYPE_U8:
1958                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
1959         case MONO_TYPE_R4:
1960                 if (cfg->r4fp)
1961                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
1962                 else
1963                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1964         case MONO_TYPE_R8:
1965                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1966         case MONO_TYPE_VALUETYPE:
1967                 if (type->data.klass->enumtype) {
1968                         type = mono_class_enum_basetype (type->data.klass);
1969                         goto handle_enum;
1970                 } else
1971                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1972         case MONO_TYPE_TYPEDBYREF:
1973                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1974         case MONO_TYPE_GENERICINST:
1975                 type = &type->data.generic_class->container_class->byval_arg;
1976                 goto handle_enum;
1977         case MONO_TYPE_VAR:
1978         case MONO_TYPE_MVAR:
1979                 /* gsharedvt */
1980                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1981         default:
1982                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1983         }
1984         return -1;
1985 }
1986
1987 //XXX this ignores if t is byref
1988 #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)))))
1989
1990 /*
1991  * target_type_is_incompatible:
1992  * @cfg: MonoCompile context
1993  *
1994  * Check that the item @arg on the evaluation stack can be stored
1995  * in the target type (can be a local, or field, etc).
1996  * The cfg arg can be used to check if we need verification or just
1997  * validity checks.
1998  *
1999  * Returns: non-0 value if arg can't be stored on a target.
2000  */
2001 static int
2002 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2003 {
2004         MonoType *simple_type;
2005         MonoClass *klass;
2006
2007         if (target->byref) {
2008                 /* FIXME: check that the pointed to types match */
2009                 if (arg->type == STACK_MP) {
2010                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
2011                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
2012                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
2013
2014                         /* if the target is native int& or same type */
2015                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
2016                                 return 0;
2017
2018                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
2019                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
2020                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
2021                                 return 0;
2022                         return 1;
2023                 }
2024                 if (arg->type == STACK_PTR)
2025                         return 0;
2026                 return 1;
2027         }
2028
2029         simple_type = mini_get_underlying_type (target);
2030         switch (simple_type->type) {
2031         case MONO_TYPE_VOID:
2032                 return 1;
2033         case MONO_TYPE_I1:
2034         case MONO_TYPE_U1:
2035         case MONO_TYPE_I2:
2036         case MONO_TYPE_U2:
2037         case MONO_TYPE_I4:
2038         case MONO_TYPE_U4:
2039                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2040                         return 1;
2041                 return 0;
2042         case MONO_TYPE_PTR:
2043                 /* STACK_MP is needed when setting pinned locals */
2044                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2045                         return 1;
2046                 return 0;
2047         case MONO_TYPE_I:
2048         case MONO_TYPE_U:
2049         case MONO_TYPE_FNPTR:
2050                 /* 
2051                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2052                  * in native int. (#688008).
2053                  */
2054                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2055                         return 1;
2056                 return 0;
2057         case MONO_TYPE_CLASS:
2058         case MONO_TYPE_STRING:
2059         case MONO_TYPE_OBJECT:
2060         case MONO_TYPE_SZARRAY:
2061         case MONO_TYPE_ARRAY:    
2062                 if (arg->type != STACK_OBJ)
2063                         return 1;
2064                 /* FIXME: check type compatibility */
2065                 return 0;
2066         case MONO_TYPE_I8:
2067         case MONO_TYPE_U8:
2068                 if (arg->type != STACK_I8)
2069                         return 1;
2070                 return 0;
2071         case MONO_TYPE_R4:
2072                 if (arg->type != cfg->r4_stack_type)
2073                         return 1;
2074                 return 0;
2075         case MONO_TYPE_R8:
2076                 if (arg->type != STACK_R8)
2077                         return 1;
2078                 return 0;
2079         case MONO_TYPE_VALUETYPE:
2080                 if (arg->type != STACK_VTYPE)
2081                         return 1;
2082                 klass = mono_class_from_mono_type (simple_type);
2083                 if (klass != arg->klass)
2084                         return 1;
2085                 return 0;
2086         case MONO_TYPE_TYPEDBYREF:
2087                 if (arg->type != STACK_VTYPE)
2088                         return 1;
2089                 klass = mono_class_from_mono_type (simple_type);
2090                 if (klass != arg->klass)
2091                         return 1;
2092                 return 0;
2093         case MONO_TYPE_GENERICINST:
2094                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2095                         MonoClass *target_class;
2096                         if (arg->type != STACK_VTYPE)
2097                                 return 1;
2098                         klass = mono_class_from_mono_type (simple_type);
2099                         target_class = mono_class_from_mono_type (target);
2100                         /* The second cases is needed when doing partial sharing */
2101                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2102                                 return 1;
2103                         return 0;
2104                 } else {
2105                         if (arg->type != STACK_OBJ)
2106                                 return 1;
2107                         /* FIXME: check type compatibility */
2108                         return 0;
2109                 }
2110         case MONO_TYPE_VAR:
2111         case MONO_TYPE_MVAR:
2112                 g_assert (cfg->gshared);
2113                 if (mini_type_var_is_vt (simple_type)) {
2114                         if (arg->type != STACK_VTYPE)
2115                                 return 1;
2116                 } else {
2117                         if (arg->type != STACK_OBJ)
2118                                 return 1;
2119                 }
2120                 return 0;
2121         default:
2122                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2123         }
2124         return 1;
2125 }
2126
2127 /*
2128  * Prepare arguments for passing to a function call.
2129  * Return a non-zero value if the arguments can't be passed to the given
2130  * signature.
2131  * The type checks are not yet complete and some conversions may need
2132  * casts on 32 or 64 bit architectures.
2133  *
2134  * FIXME: implement this using target_type_is_incompatible ()
2135  */
2136 static int
2137 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2138 {
2139         MonoType *simple_type;
2140         int i;
2141
2142         if (sig->hasthis) {
2143                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2144                         return 1;
2145                 args++;
2146         }
2147         for (i = 0; i < sig->param_count; ++i) {
2148                 if (sig->params [i]->byref) {
2149                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2150                                 return 1;
2151                         continue;
2152                 }
2153                 simple_type = mini_get_underlying_type (sig->params [i]);
2154 handle_enum:
2155                 switch (simple_type->type) {
2156                 case MONO_TYPE_VOID:
2157                         return 1;
2158                         continue;
2159                 case MONO_TYPE_I1:
2160                 case MONO_TYPE_U1:
2161                 case MONO_TYPE_I2:
2162                 case MONO_TYPE_U2:
2163                 case MONO_TYPE_I4:
2164                 case MONO_TYPE_U4:
2165                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2166                                 return 1;
2167                         continue;
2168                 case MONO_TYPE_I:
2169                 case MONO_TYPE_U:
2170                 case MONO_TYPE_PTR:
2171                 case MONO_TYPE_FNPTR:
2172                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2173                                 return 1;
2174                         continue;
2175                 case MONO_TYPE_CLASS:
2176                 case MONO_TYPE_STRING:
2177                 case MONO_TYPE_OBJECT:
2178                 case MONO_TYPE_SZARRAY:
2179                 case MONO_TYPE_ARRAY:    
2180                         if (args [i]->type != STACK_OBJ)
2181                                 return 1;
2182                         continue;
2183                 case MONO_TYPE_I8:
2184                 case MONO_TYPE_U8:
2185                         if (args [i]->type != STACK_I8)
2186                                 return 1;
2187                         continue;
2188                 case MONO_TYPE_R4:
2189                         if (args [i]->type != cfg->r4_stack_type)
2190                                 return 1;
2191                         continue;
2192                 case MONO_TYPE_R8:
2193                         if (args [i]->type != STACK_R8)
2194                                 return 1;
2195                         continue;
2196                 case MONO_TYPE_VALUETYPE:
2197                         if (simple_type->data.klass->enumtype) {
2198                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2199                                 goto handle_enum;
2200                         }
2201                         if (args [i]->type != STACK_VTYPE)
2202                                 return 1;
2203                         continue;
2204                 case MONO_TYPE_TYPEDBYREF:
2205                         if (args [i]->type != STACK_VTYPE)
2206                                 return 1;
2207                         continue;
2208                 case MONO_TYPE_GENERICINST:
2209                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2210                         goto handle_enum;
2211                 case MONO_TYPE_VAR:
2212                 case MONO_TYPE_MVAR:
2213                         /* gsharedvt */
2214                         if (args [i]->type != STACK_VTYPE)
2215                                 return 1;
2216                         continue;
2217                 default:
2218                         g_error ("unknown type 0x%02x in check_call_signature",
2219                                  simple_type->type);
2220                 }
2221         }
2222         return 0;
2223 }
2224
2225 static int
2226 callvirt_to_call (int opcode)
2227 {
2228         switch (opcode) {
2229         case OP_CALL_MEMBASE:
2230                 return OP_CALL;
2231         case OP_VOIDCALL_MEMBASE:
2232                 return OP_VOIDCALL;
2233         case OP_FCALL_MEMBASE:
2234                 return OP_FCALL;
2235         case OP_RCALL_MEMBASE:
2236                 return OP_RCALL;
2237         case OP_VCALL_MEMBASE:
2238                 return OP_VCALL;
2239         case OP_LCALL_MEMBASE:
2240                 return OP_LCALL;
2241         default:
2242                 g_assert_not_reached ();
2243         }
2244
2245         return -1;
2246 }
2247
2248 static int
2249 callvirt_to_call_reg (int opcode)
2250 {
2251         switch (opcode) {
2252         case OP_CALL_MEMBASE:
2253                 return OP_CALL_REG;
2254         case OP_VOIDCALL_MEMBASE:
2255                 return OP_VOIDCALL_REG;
2256         case OP_FCALL_MEMBASE:
2257                 return OP_FCALL_REG;
2258         case OP_RCALL_MEMBASE:
2259                 return OP_RCALL_REG;
2260         case OP_VCALL_MEMBASE:
2261                 return OP_VCALL_REG;
2262         case OP_LCALL_MEMBASE:
2263                 return OP_LCALL_REG;
2264         default:
2265                 g_assert_not_reached ();
2266         }
2267
2268         return -1;
2269 }
2270
2271 /* Either METHOD or IMT_ARG needs to be set */
2272 static void
2273 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2274 {
2275         int method_reg;
2276
2277         if (COMPILE_LLVM (cfg)) {
2278                 if (imt_arg) {
2279                         method_reg = alloc_preg (cfg);
2280                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2281                 } else {
2282                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2283                         method_reg = ins->dreg;
2284                 }
2285
2286 #ifdef ENABLE_LLVM
2287                 call->imt_arg_reg = method_reg;
2288 #endif
2289                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2290                 return;
2291         }
2292
2293         if (imt_arg) {
2294                 method_reg = alloc_preg (cfg);
2295                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2296         } else {
2297                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2298                 method_reg = ins->dreg;
2299         }
2300
2301         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2302 }
2303
2304 static MonoJumpInfo *
2305 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2306 {
2307         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2308
2309         ji->ip.i = ip;
2310         ji->type = type;
2311         ji->data.target = target;
2312
2313         return ji;
2314 }
2315
2316 static int
2317 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2318 {
2319         if (cfg->gshared)
2320                 return mono_class_check_context_used (klass);
2321         else
2322                 return 0;
2323 }
2324
2325 static int
2326 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2327 {
2328         if (cfg->gshared)
2329                 return mono_method_check_context_used (method);
2330         else
2331                 return 0;
2332 }
2333
2334 /*
2335  * check_method_sharing:
2336  *
2337  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2338  */
2339 static void
2340 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2341 {
2342         gboolean pass_vtable = FALSE;
2343         gboolean pass_mrgctx = FALSE;
2344
2345         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2346                 (mono_class_is_ginst (cmethod->klass) || mono_class_is_gtd (cmethod->klass))) {
2347                 gboolean sharable = FALSE;
2348
2349                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2350                         sharable = TRUE;
2351
2352                 /*
2353                  * Pass vtable iff target method might
2354                  * be shared, which means that sharing
2355                  * is enabled for its class and its
2356                  * context is sharable (and it's not a
2357                  * generic method).
2358                  */
2359                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2360                         pass_vtable = TRUE;
2361         }
2362
2363         if (mini_method_get_context (cmethod) &&
2364                 mini_method_get_context (cmethod)->method_inst) {
2365                 g_assert (!pass_vtable);
2366
2367                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2368                         pass_mrgctx = TRUE;
2369                 } else {
2370                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2371                                 pass_mrgctx = TRUE;
2372                 }
2373         }
2374
2375         if (out_pass_vtable)
2376                 *out_pass_vtable = pass_vtable;
2377         if (out_pass_mrgctx)
2378                 *out_pass_mrgctx = pass_mrgctx;
2379 }
2380
2381 inline static MonoCallInst *
2382 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2383                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2384 {
2385         MonoType *sig_ret;
2386         MonoCallInst *call;
2387 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2388         int i;
2389 #endif
2390
2391         if (cfg->llvm_only)
2392                 tail = FALSE;
2393
2394         if (tail) {
2395                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2396
2397                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2398         } else
2399                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2400
2401         call->args = args;
2402         call->signature = sig;
2403         call->rgctx_reg = rgctx;
2404         sig_ret = mini_get_underlying_type (sig->ret);
2405
2406         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2407
2408         if (tail) {
2409                 if (mini_type_is_vtype (sig_ret)) {
2410                         call->vret_var = cfg->vret_addr;
2411                         //g_assert_not_reached ();
2412                 }
2413         } else if (mini_type_is_vtype (sig_ret)) {
2414                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2415                 MonoInst *loada;
2416
2417                 temp->backend.is_pinvoke = sig->pinvoke;
2418
2419                 /*
2420                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2421                  * address of return value to increase optimization opportunities.
2422                  * Before vtype decomposition, the dreg of the call ins itself represents the
2423                  * fact the call modifies the return value. After decomposition, the call will
2424                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2425                  * will be transformed into an LDADDR.
2426                  */
2427                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2428                 loada->dreg = alloc_preg (cfg);
2429                 loada->inst_p0 = temp;
2430                 /* We reference the call too since call->dreg could change during optimization */
2431                 loada->inst_p1 = call;
2432                 MONO_ADD_INS (cfg->cbb, loada);
2433
2434                 call->inst.dreg = temp->dreg;
2435
2436                 call->vret_var = loada;
2437         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2438                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2439
2440 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2441         if (COMPILE_SOFT_FLOAT (cfg)) {
2442                 /* 
2443                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2444                  * an icall, but that cannot be done during the call sequence since it would clobber
2445                  * the call registers + the stack. So we do it before emitting the call.
2446                  */
2447                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2448                         MonoType *t;
2449                         MonoInst *in = call->args [i];
2450
2451                         if (i >= sig->hasthis)
2452                                 t = sig->params [i - sig->hasthis];
2453                         else
2454                                 t = &mono_defaults.int_class->byval_arg;
2455                         t = mono_type_get_underlying_type (t);
2456
2457                         if (!t->byref && t->type == MONO_TYPE_R4) {
2458                                 MonoInst *iargs [1];
2459                                 MonoInst *conv;
2460
2461                                 iargs [0] = in;
2462                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2463
2464                                 /* The result will be in an int vreg */
2465                                 call->args [i] = conv;
2466                         }
2467                 }
2468         }
2469 #endif
2470
2471         call->need_unbox_trampoline = unbox_trampoline;
2472
2473 #ifdef ENABLE_LLVM
2474         if (COMPILE_LLVM (cfg))
2475                 mono_llvm_emit_call (cfg, call);
2476         else
2477                 mono_arch_emit_call (cfg, call);
2478 #else
2479         mono_arch_emit_call (cfg, call);
2480 #endif
2481
2482         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2483         cfg->flags |= MONO_CFG_HAS_CALLS;
2484         
2485         return call;
2486 }
2487
2488 static void
2489 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2490 {
2491         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2492         cfg->uses_rgctx_reg = TRUE;
2493         call->rgctx_reg = TRUE;
2494 #ifdef ENABLE_LLVM
2495         call->rgctx_arg_reg = rgctx_reg;
2496 #endif
2497 }       
2498
2499 inline static MonoInst*
2500 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2501 {
2502         MonoCallInst *call;
2503         MonoInst *ins;
2504         int rgctx_reg = -1;
2505         gboolean check_sp = FALSE;
2506
2507         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2508                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2509
2510                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2511                         check_sp = TRUE;
2512         }
2513
2514         if (rgctx_arg) {
2515                 rgctx_reg = mono_alloc_preg (cfg);
2516                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2517         }
2518
2519         if (check_sp) {
2520                 if (!cfg->stack_inbalance_var)
2521                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2522
2523                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2524                 ins->dreg = cfg->stack_inbalance_var->dreg;
2525                 MONO_ADD_INS (cfg->cbb, ins);
2526         }
2527
2528         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2529
2530         call->inst.sreg1 = addr->dreg;
2531
2532         if (imt_arg)
2533                 emit_imt_argument (cfg, call, NULL, imt_arg);
2534
2535         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2536
2537         if (check_sp) {
2538                 int sp_reg;
2539
2540                 sp_reg = mono_alloc_preg (cfg);
2541
2542                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2543                 ins->dreg = sp_reg;
2544                 MONO_ADD_INS (cfg->cbb, ins);
2545
2546                 /* Restore the stack so we don't crash when throwing the exception */
2547                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2548                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2549                 MONO_ADD_INS (cfg->cbb, ins);
2550
2551                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2552                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2553         }
2554
2555         if (rgctx_arg)
2556                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2557
2558         return (MonoInst*)call;
2559 }
2560
2561 static MonoInst*
2562 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2563
2564 static MonoInst*
2565 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2566
2567 static MonoInst*
2568 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2569                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2570 {
2571 #ifndef DISABLE_REMOTING
2572         gboolean might_be_remote = FALSE;
2573 #endif
2574         gboolean virtual_ = this_ins != NULL;
2575         gboolean enable_for_aot = TRUE;
2576         int context_used;
2577         MonoCallInst *call;
2578         MonoInst *call_target = NULL;
2579         int rgctx_reg = 0;
2580         gboolean need_unbox_trampoline;
2581
2582         if (!sig)
2583                 sig = mono_method_signature (method);
2584
2585         if (cfg->llvm_only && (mono_class_is_interface (method->klass)))
2586                 g_assert_not_reached ();
2587
2588         if (rgctx_arg) {
2589                 rgctx_reg = mono_alloc_preg (cfg);
2590                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2591         }
2592
2593         if (method->string_ctor) {
2594                 /* Create the real signature */
2595                 /* FIXME: Cache these */
2596                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2597                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2598
2599                 sig = ctor_sig;
2600         }
2601
2602         context_used = mini_method_check_context_used (cfg, method);
2603
2604 #ifndef DISABLE_REMOTING
2605         might_be_remote = this_ins && sig->hasthis &&
2606                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2607                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2608
2609         if (might_be_remote && context_used) {
2610                 MonoInst *addr;
2611
2612                 g_assert (cfg->gshared);
2613
2614                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2615
2616                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2617         }
2618 #endif
2619
2620         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2621                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2622
2623         need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass);
2624
2625         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2626
2627 #ifndef DISABLE_REMOTING
2628         if (might_be_remote)
2629                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2630         else
2631 #endif
2632                 call->method = method;
2633         call->inst.flags |= MONO_INST_HAS_METHOD;
2634         call->inst.inst_left = this_ins;
2635         call->tail_call = tail;
2636
2637         if (virtual_) {
2638                 int vtable_reg, slot_reg, this_reg;
2639                 int offset;
2640
2641                 this_reg = this_ins->dreg;
2642
2643                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2644                         MonoInst *dummy_use;
2645
2646                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2647
2648                         /* Make a call to delegate->invoke_impl */
2649                         call->inst.inst_basereg = this_reg;
2650                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2651                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2652
2653                         /* We must emit a dummy use here because the delegate trampoline will
2654                         replace the 'this' argument with the delegate target making this activation
2655                         no longer a root for the delegate.
2656                         This is an issue for delegates that target collectible code such as dynamic
2657                         methods of GC'able assemblies.
2658
2659                         For a test case look into #667921.
2660
2661                         FIXME: a dummy use is not the best way to do it as the local register allocator
2662                         will put it on a caller save register and spil it around the call. 
2663                         Ideally, we would either put it on a callee save register or only do the store part.  
2664                          */
2665                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2666
2667                         return (MonoInst*)call;
2668                 }
2669
2670                 if ((!cfg->compile_aot || enable_for_aot) && 
2671                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2672                          (MONO_METHOD_IS_FINAL (method) &&
2673                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2674                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2675                         /* 
2676                          * the method is not virtual, we just need to ensure this is not null
2677                          * and then we can call the method directly.
2678                          */
2679 #ifndef DISABLE_REMOTING
2680                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2681                                 /* 
2682                                  * The check above ensures method is not gshared, this is needed since
2683                                  * gshared methods can't have wrappers.
2684                                  */
2685                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2686                         }
2687 #endif
2688
2689                         if (!method->string_ctor)
2690                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2691
2692                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2693                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2694                         /*
2695                          * the method is virtual, but we can statically dispatch since either
2696                          * it's class or the method itself are sealed.
2697                          * But first we need to ensure it's not a null reference.
2698                          */
2699                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2700
2701                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2702                 } else if (call_target) {
2703                         vtable_reg = alloc_preg (cfg);
2704                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2705
2706                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2707                         call->inst.sreg1 = call_target->dreg;
2708                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2709                 } else {
2710                         vtable_reg = alloc_preg (cfg);
2711                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2712                         if (mono_class_is_interface (method->klass)) {
2713                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2714                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2715                                 slot_reg = vtable_reg;
2716                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2717                         } else {
2718                                 slot_reg = vtable_reg;
2719                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2720                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2721                                 if (imt_arg) {
2722                                         g_assert (mono_method_signature (method)->generic_param_count);
2723                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2724                                 }
2725                         }
2726
2727                         call->inst.sreg1 = slot_reg;
2728                         call->inst.inst_offset = offset;
2729                         call->is_virtual = TRUE;
2730                 }
2731         }
2732
2733         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2734
2735         if (rgctx_arg)
2736                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2737
2738         return (MonoInst*)call;
2739 }
2740
2741 MonoInst*
2742 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2743 {
2744         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2745 }
2746
2747 MonoInst*
2748 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2749                                            MonoInst **args)
2750 {
2751         MonoCallInst *call;
2752
2753         g_assert (sig);
2754
2755         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2756         call->fptr = func;
2757
2758         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2759
2760         return (MonoInst*)call;
2761 }
2762
2763 MonoInst*
2764 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2765 {
2766         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2767
2768         g_assert (info);
2769
2770         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2771 }
2772
2773 /*
2774  * mono_emit_abs_call:
2775  *
2776  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2777  */
2778 inline static MonoInst*
2779 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2780                                         MonoMethodSignature *sig, MonoInst **args)
2781 {
2782         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2783         MonoInst *ins;
2784
2785         /* 
2786          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2787          * handle it.
2788          */
2789         if (cfg->abs_patches == NULL)
2790                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2791         g_hash_table_insert (cfg->abs_patches, ji, ji);
2792         ins = mono_emit_native_call (cfg, ji, sig, args);
2793         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2794         return ins;
2795 }
2796
2797 static MonoMethodSignature*
2798 sig_to_rgctx_sig (MonoMethodSignature *sig)
2799 {
2800         // FIXME: memory allocation
2801         MonoMethodSignature *res;
2802         int i;
2803
2804         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2805         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2806         res->param_count = sig->param_count + 1;
2807         for (i = 0; i < sig->param_count; ++i)
2808                 res->params [i] = sig->params [i];
2809         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
2810         return res;
2811 }
2812
2813 /* Make an indirect call to FSIG passing an additional argument */
2814 static MonoInst*
2815 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
2816 {
2817         MonoMethodSignature *csig;
2818         MonoInst *args_buf [16];
2819         MonoInst **args;
2820         int i, pindex, tmp_reg;
2821
2822         /* Make a call with an rgctx/extra arg */
2823         if (fsig->param_count + 2 < 16)
2824                 args = args_buf;
2825         else
2826                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
2827         pindex = 0;
2828         if (fsig->hasthis)
2829                 args [pindex ++] = orig_args [0];
2830         for (i = 0; i < fsig->param_count; ++i)
2831                 args [pindex ++] = orig_args [fsig->hasthis + i];
2832         tmp_reg = alloc_preg (cfg);
2833         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
2834         csig = sig_to_rgctx_sig (fsig);
2835         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
2836 }
2837
2838 /* Emit an indirect call to the function descriptor ADDR */
2839 static MonoInst*
2840 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
2841 {
2842         int addr_reg, arg_reg;
2843         MonoInst *call_target;
2844
2845         g_assert (cfg->llvm_only);
2846
2847         /*
2848          * addr points to a <addr, arg> pair, load both of them, and
2849          * make a call to addr, passing arg as an extra arg.
2850          */
2851         addr_reg = alloc_preg (cfg);
2852         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
2853         arg_reg = alloc_preg (cfg);
2854         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
2855
2856         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
2857 }
2858
2859 static gboolean
2860 direct_icalls_enabled (MonoCompile *cfg)
2861 {
2862         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
2863 #ifdef TARGET_AMD64
2864         if (cfg->compile_llvm && !cfg->llvm_only)
2865                 return FALSE;
2866 #endif
2867         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
2868                 return FALSE;
2869         return TRUE;
2870 }
2871
2872 MonoInst*
2873 mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
2874 {
2875         /*
2876          * Call the jit icall without a wrapper if possible.
2877          * The wrapper is needed for the following reasons:
2878          * - to handle exceptions thrown using mono_raise_exceptions () from the
2879          *   icall function. The EH code needs the lmf frame pushed by the
2880          *   wrapper to be able to unwind back to managed code.
2881          * - to be able to do stack walks for asynchronously suspended
2882          *   threads when debugging.
2883          */
2884         if (info->no_raise && direct_icalls_enabled (cfg)) {
2885                 char *name;
2886                 int costs;
2887
2888                 if (!info->wrapper_method) {
2889                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
2890                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
2891                         g_free (name);
2892                         mono_memory_barrier ();
2893                 }
2894
2895                 /*
2896                  * Inline the wrapper method, which is basically a call to the C icall, and
2897                  * an exception check.
2898                  */
2899                 costs = inline_method (cfg, info->wrapper_method, NULL,
2900                                                            args, NULL, il_offset, TRUE);
2901                 g_assert (costs > 0);
2902                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
2903
2904                 return args [0];
2905         } else {
2906                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2907         }
2908 }
2909  
2910 static MonoInst*
2911 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2912 {
2913         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2914                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2915                         int widen_op = -1;
2916
2917                         /* 
2918                          * Native code might return non register sized integers 
2919                          * without initializing the upper bits.
2920                          */
2921                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2922                         case OP_LOADI1_MEMBASE:
2923                                 widen_op = OP_ICONV_TO_I1;
2924                                 break;
2925                         case OP_LOADU1_MEMBASE:
2926                                 widen_op = OP_ICONV_TO_U1;
2927                                 break;
2928                         case OP_LOADI2_MEMBASE:
2929                                 widen_op = OP_ICONV_TO_I2;
2930                                 break;
2931                         case OP_LOADU2_MEMBASE:
2932                                 widen_op = OP_ICONV_TO_U2;
2933                                 break;
2934                         default:
2935                                 break;
2936                         }
2937
2938                         if (widen_op != -1) {
2939                                 int dreg = alloc_preg (cfg);
2940                                 MonoInst *widen;
2941
2942                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2943                                 widen->type = ins->type;
2944                                 ins = widen;
2945                         }
2946                 }
2947         }
2948
2949         return ins;
2950 }
2951
2952
2953 static void
2954 emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
2955 {
2956         MonoInst *args [16];
2957
2958         args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
2959         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
2960
2961         mono_emit_jit_icall (cfg, mono_throw_method_access, args);
2962 }
2963
2964 static MonoMethod*
2965 get_memcpy_method (void)
2966 {
2967         static MonoMethod *memcpy_method = NULL;
2968         if (!memcpy_method) {
2969                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2970                 if (!memcpy_method)
2971                         g_error ("Old corlib found. Install a new one");
2972         }
2973         return memcpy_method;
2974 }
2975
2976 static void
2977 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
2978 {
2979         MonoClassField *field;
2980         gpointer iter = NULL;
2981
2982         while ((field = mono_class_get_fields (klass, &iter))) {
2983                 int foffset;
2984
2985                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2986                         continue;
2987                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2988                 if (mini_type_is_reference (mono_field_get_type (field))) {
2989                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2990                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2991                 } else {
2992                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2993                         if (field_class->has_references)
2994                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
2995                 }
2996         }
2997 }
2998
2999 static void
3000 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3001 {
3002         int card_table_shift_bits;
3003         gpointer card_table_mask;
3004         guint8 *card_table;
3005         MonoInst *dummy_use;
3006         int nursery_shift_bits;
3007         size_t nursery_size;
3008
3009         if (!cfg->gen_write_barriers)
3010                 return;
3011
3012         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3013
3014         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3015
3016         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3017                 MonoInst *wbarrier;
3018
3019                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3020                 wbarrier->sreg1 = ptr->dreg;
3021                 wbarrier->sreg2 = value->dreg;
3022                 MONO_ADD_INS (cfg->cbb, wbarrier);
3023         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3024                 int offset_reg = alloc_preg (cfg);
3025                 int card_reg;
3026                 MonoInst *ins;
3027
3028                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3029                 if (card_table_mask)
3030                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3031
3032                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3033                  * IMM's larger than 32bits.
3034                  */
3035                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3036                 card_reg = ins->dreg;
3037
3038                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3039                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3040         } else {
3041                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3042                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3043         }
3044
3045         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3046 }
3047
3048 static gboolean
3049 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3050 {
3051         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3052         unsigned need_wb = 0;
3053
3054         if (align == 0)
3055                 align = 4;
3056
3057         /*types with references can't have alignment smaller than sizeof(void*) */
3058         if (align < SIZEOF_VOID_P)
3059                 return FALSE;
3060
3061         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3062         if (size > 32 * SIZEOF_VOID_P)
3063                 return FALSE;
3064
3065         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3066
3067         /* We don't unroll more than 5 stores to avoid code bloat. */
3068         if (size > 5 * SIZEOF_VOID_P) {
3069                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3070                 size += (SIZEOF_VOID_P - 1);
3071                 size &= ~(SIZEOF_VOID_P - 1);
3072
3073                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3074                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3075                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3076                 return TRUE;
3077         }
3078
3079         destreg = iargs [0]->dreg;
3080         srcreg = iargs [1]->dreg;
3081         offset = 0;
3082
3083         dest_ptr_reg = alloc_preg (cfg);
3084         tmp_reg = alloc_preg (cfg);
3085
3086         /*tmp = dreg*/
3087         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3088
3089         while (size >= SIZEOF_VOID_P) {
3090                 MonoInst *load_inst;
3091                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3092                 load_inst->dreg = tmp_reg;
3093                 load_inst->inst_basereg = srcreg;
3094                 load_inst->inst_offset = offset;
3095                 MONO_ADD_INS (cfg->cbb, load_inst);
3096
3097                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3098
3099                 if (need_wb & 0x1)
3100                         emit_write_barrier (cfg, iargs [0], load_inst);
3101
3102                 offset += SIZEOF_VOID_P;
3103                 size -= SIZEOF_VOID_P;
3104                 need_wb >>= 1;
3105
3106                 /*tmp += sizeof (void*)*/
3107                 if (size >= SIZEOF_VOID_P) {
3108                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3109                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3110                 }
3111         }
3112
3113         /* Those cannot be references since size < sizeof (void*) */
3114         while (size >= 4) {
3115                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3116                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3117                 offset += 4;
3118                 size -= 4;
3119         }
3120
3121         while (size >= 2) {
3122                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3123                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3124                 offset += 2;
3125                 size -= 2;
3126         }
3127
3128         while (size >= 1) {
3129                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3130                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3131                 offset += 1;
3132                 size -= 1;
3133         }
3134
3135         return TRUE;
3136 }
3137
3138 /*
3139  * Emit code to copy a valuetype of type @klass whose address is stored in
3140  * @src->dreg to memory whose address is stored at @dest->dreg.
3141  */
3142 void
3143 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3144 {
3145         MonoInst *iargs [4];
3146         int n;
3147         guint32 align = 0;
3148         MonoMethod *memcpy_method;
3149         MonoInst *size_ins = NULL;
3150         MonoInst *memcpy_ins = NULL;
3151
3152         g_assert (klass);
3153         if (cfg->gshared)
3154                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3155
3156         /*
3157          * This check breaks with spilled vars... need to handle it during verification anyway.
3158          * g_assert (klass && klass == src->klass && klass == dest->klass);
3159          */
3160
3161         if (mini_is_gsharedvt_klass (klass)) {
3162                 g_assert (!native);
3163                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3164                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3165         }
3166
3167         if (native)
3168                 n = mono_class_native_size (klass, &align);
3169         else
3170                 n = mono_class_value_size (klass, &align);
3171
3172         /* if native is true there should be no references in the struct */
3173         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3174                 /* Avoid barriers when storing to the stack */
3175                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3176                           (dest->opcode == OP_LDADDR))) {
3177                         int context_used;
3178
3179                         iargs [0] = dest;
3180                         iargs [1] = src;
3181
3182                         context_used = mini_class_check_context_used (cfg, klass);
3183
3184                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3185                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3186                                 return;
3187                         } else if (context_used) {
3188                                 iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3189                         }  else {
3190                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3191                                 if (!cfg->compile_aot)
3192                                         mono_class_compute_gc_descriptor (klass);
3193                         }
3194
3195                         if (size_ins)
3196                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3197                         else
3198                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3199                         return;
3200                 }
3201         }
3202
3203         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3204                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3205                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3206         } else {
3207                 iargs [0] = dest;
3208                 iargs [1] = src;
3209                 if (size_ins)
3210                         iargs [2] = size_ins;
3211                 else
3212                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3213                 
3214                 memcpy_method = get_memcpy_method ();
3215                 if (memcpy_ins)
3216                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3217                 else
3218                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3219         }
3220 }
3221
3222 static MonoMethod*
3223 get_memset_method (void)
3224 {
3225         static MonoMethod *memset_method = NULL;
3226         if (!memset_method) {
3227                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3228                 if (!memset_method)
3229                         g_error ("Old corlib found. Install a new one");
3230         }
3231         return memset_method;
3232 }
3233
3234 void
3235 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3236 {
3237         MonoInst *iargs [3];
3238         int n;
3239         guint32 align;
3240         MonoMethod *memset_method;
3241         MonoInst *size_ins = NULL;
3242         MonoInst *bzero_ins = NULL;
3243         static MonoMethod *bzero_method;
3244
3245         /* FIXME: Optimize this for the case when dest is an LDADDR */
3246         mono_class_init (klass);
3247         if (mini_is_gsharedvt_klass (klass)) {
3248                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3249                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3250                 if (!bzero_method)
3251                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3252                 g_assert (bzero_method);
3253                 iargs [0] = dest;
3254                 iargs [1] = size_ins;
3255                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3256                 return;
3257         }
3258
3259         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3260
3261         n = mono_class_value_size (klass, &align);
3262
3263         if (n <= sizeof (gpointer) * 8) {
3264                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3265         }
3266         else {
3267                 memset_method = get_memset_method ();
3268                 iargs [0] = dest;
3269                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3270                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3271                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3272         }
3273 }
3274
3275 /*
3276  * emit_get_rgctx:
3277  *
3278  *   Emit IR to return either the this pointer for instance method,
3279  * or the mrgctx for static methods.
3280  */
3281 static MonoInst*
3282 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3283 {
3284         MonoInst *this_ins = NULL;
3285
3286         g_assert (cfg->gshared);
3287
3288         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3289                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3290                 !method->klass->valuetype)
3291                 EMIT_NEW_VARLOAD (cfg, this_ins, cfg->this_arg, &mono_defaults.object_class->byval_arg);
3292
3293         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3294                 MonoInst *mrgctx_loc, *mrgctx_var;
3295
3296                 g_assert (!this_ins);
3297                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3298
3299                 mrgctx_loc = mono_get_vtable_var (cfg);
3300                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3301
3302                 return mrgctx_var;
3303         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3304                 MonoInst *vtable_loc, *vtable_var;
3305
3306                 g_assert (!this_ins);
3307
3308                 vtable_loc = mono_get_vtable_var (cfg);
3309                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3310
3311                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3312                         MonoInst *mrgctx_var = vtable_var;
3313                         int vtable_reg;
3314
3315                         vtable_reg = alloc_preg (cfg);
3316                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3317                         vtable_var->type = STACK_PTR;
3318                 }
3319
3320                 return vtable_var;
3321         } else {
3322                 MonoInst *ins;
3323                 int vtable_reg;
3324         
3325                 vtable_reg = alloc_preg (cfg);
3326                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3327                 return ins;
3328         }
3329 }
3330
3331 static MonoJumpInfoRgctxEntry *
3332 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3333 {
3334         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3335         res->method = method;
3336         res->in_mrgctx = in_mrgctx;
3337         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3338         res->data->type = patch_type;
3339         res->data->data.target = patch_data;
3340         res->info_type = info_type;
3341
3342         return res;
3343 }
3344
3345 static inline MonoInst*
3346 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3347 {
3348         MonoInst *args [16];
3349         MonoInst *call;
3350
3351         // FIXME: No fastpath since the slot is not a compile time constant
3352         args [0] = rgctx;
3353         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3354         if (entry->in_mrgctx)
3355                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3356         else
3357                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3358         return call;
3359 #if 0
3360         /*
3361          * FIXME: This can be called during decompose, which is a problem since it creates
3362          * new bblocks.
3363          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3364          */
3365         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3366         gboolean mrgctx;
3367         MonoBasicBlock *is_null_bb, *end_bb;
3368         MonoInst *res, *ins, *call;
3369         MonoInst *args[16];
3370
3371         slot = mini_get_rgctx_entry_slot (entry);
3372
3373         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3374         index = MONO_RGCTX_SLOT_INDEX (slot);
3375         if (mrgctx)
3376                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3377         for (depth = 0; ; ++depth) {
3378                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3379
3380                 if (index < size - 1)
3381                         break;
3382                 index -= size - 1;
3383         }
3384
3385         NEW_BBLOCK (cfg, end_bb);
3386         NEW_BBLOCK (cfg, is_null_bb);
3387
3388         if (mrgctx) {
3389                 rgctx_reg = rgctx->dreg;
3390         } else {
3391                 rgctx_reg = alloc_preg (cfg);
3392
3393                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3394                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3395                 NEW_BBLOCK (cfg, is_null_bb);
3396
3397                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3398                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3399         }
3400
3401         for (i = 0; i < depth; ++i) {
3402                 int array_reg = alloc_preg (cfg);
3403
3404                 /* load ptr to next array */
3405                 if (mrgctx && i == 0)
3406                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3407                 else
3408                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3409                 rgctx_reg = array_reg;
3410                 /* is the ptr null? */
3411                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3412                 /* if yes, jump to actual trampoline */
3413                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3414         }
3415
3416         /* fetch slot */
3417         val_reg = alloc_preg (cfg);
3418         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3419         /* is the slot null? */
3420         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3421         /* if yes, jump to actual trampoline */
3422         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3423
3424         /* Fastpath */
3425         res_reg = alloc_preg (cfg);
3426         MONO_INST_NEW (cfg, ins, OP_MOVE);
3427         ins->dreg = res_reg;
3428         ins->sreg1 = val_reg;
3429         MONO_ADD_INS (cfg->cbb, ins);
3430         res = ins;
3431         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3432
3433         /* Slowpath */
3434         MONO_START_BB (cfg, is_null_bb);
3435         args [0] = rgctx;
3436         EMIT_NEW_ICONST (cfg, args [1], index);
3437         if (mrgctx)
3438                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3439         else
3440                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3441         MONO_INST_NEW (cfg, ins, OP_MOVE);
3442         ins->dreg = res_reg;
3443         ins->sreg1 = call->dreg;
3444         MONO_ADD_INS (cfg->cbb, ins);
3445         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3446
3447         MONO_START_BB (cfg, end_bb);
3448
3449         return res;
3450 #endif
3451 }
3452
3453 /*
3454  * emit_rgctx_fetch:
3455  *
3456  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3457  * given by RGCTX.
3458  */
3459 static inline MonoInst*
3460 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3461 {
3462         if (cfg->llvm_only)
3463                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3464         else
3465                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3466 }
3467
3468 MonoInst*
3469 mini_emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3470                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3471 {
3472         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);
3473         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3474
3475         return emit_rgctx_fetch (cfg, rgctx, entry);
3476 }
3477
3478 static MonoInst*
3479 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3480                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3481 {
3482         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);
3483         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3484
3485         return emit_rgctx_fetch (cfg, rgctx, entry);
3486 }
3487
3488 static MonoInst*
3489 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3490                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3491 {
3492         MonoJumpInfoGSharedVtCall *call_info;
3493         MonoJumpInfoRgctxEntry *entry;
3494         MonoInst *rgctx;
3495
3496         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3497         call_info->sig = sig;
3498         call_info->method = cmethod;
3499
3500         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);
3501         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3502
3503         return emit_rgctx_fetch (cfg, rgctx, entry);
3504 }
3505
3506 /*
3507  * emit_get_rgctx_virt_method:
3508  *
3509  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3510  */
3511 static MonoInst*
3512 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3513                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3514 {
3515         MonoJumpInfoVirtMethod *info;
3516         MonoJumpInfoRgctxEntry *entry;
3517         MonoInst *rgctx;
3518
3519         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3520         info->klass = klass;
3521         info->method = virt_method;
3522
3523         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);
3524         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3525
3526         return emit_rgctx_fetch (cfg, rgctx, entry);
3527 }
3528
3529 static MonoInst*
3530 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3531                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3532 {
3533         MonoJumpInfoRgctxEntry *entry;
3534         MonoInst *rgctx;
3535
3536         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);
3537         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3538
3539         return emit_rgctx_fetch (cfg, rgctx, entry);
3540 }
3541
3542 /*
3543  * emit_get_rgctx_method:
3544  *
3545  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3546  * normal constants, else emit a load from the rgctx.
3547  */
3548 static MonoInst*
3549 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3550                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3551 {
3552         if (!context_used) {
3553                 MonoInst *ins;
3554
3555                 switch (rgctx_type) {
3556                 case MONO_RGCTX_INFO_METHOD:
3557                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3558                         return ins;
3559                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3560                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3561                         return ins;
3562                 default:
3563                         g_assert_not_reached ();
3564                 }
3565         } else {
3566                 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);
3567                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3568
3569                 return emit_rgctx_fetch (cfg, rgctx, entry);
3570         }
3571 }
3572
3573 static MonoInst*
3574 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3575                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3576 {
3577         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);
3578         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3579
3580         return emit_rgctx_fetch (cfg, rgctx, entry);
3581 }
3582
3583 static int
3584 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3585 {
3586         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3587         MonoRuntimeGenericContextInfoTemplate *template_;
3588         int i, idx;
3589
3590         g_assert (info);
3591
3592         for (i = 0; i < info->num_entries; ++i) {
3593                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3594
3595                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3596                         return i;
3597         }
3598
3599         if (info->num_entries == info->count_entries) {
3600                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3601                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3602
3603                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3604
3605                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3606                 info->entries = new_entries;
3607                 info->count_entries = new_count_entries;
3608         }
3609
3610         idx = info->num_entries;
3611         template_ = &info->entries [idx];
3612         template_->info_type = rgctx_type;
3613         template_->data = data;
3614
3615         info->num_entries ++;
3616
3617         return idx;
3618 }
3619
3620 /*
3621  * emit_get_gsharedvt_info:
3622  *
3623  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3624  */
3625 static MonoInst*
3626 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3627 {
3628         MonoInst *ins;
3629         int idx, dreg;
3630
3631         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3632         /* Load info->entries [idx] */
3633         dreg = alloc_preg (cfg);
3634         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3635
3636         return ins;
3637 }
3638
3639 static MonoInst*
3640 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3641 {
3642         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3643 }
3644
3645 /*
3646  * On return the caller must check @klass for load errors.
3647  */
3648 static void
3649 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3650 {
3651         MonoInst *vtable_arg;
3652         int context_used;
3653
3654         context_used = mini_class_check_context_used (cfg, klass);
3655
3656         if (context_used) {
3657                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
3658                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3659         } else {
3660                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3661
3662                 if (!vtable)
3663                         return;
3664                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3665         }
3666
3667         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3668                 MonoInst *ins;
3669
3670                 /*
3671                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3672                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3673                  */
3674                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3675                 ins->sreg1 = vtable_arg->dreg;
3676                 MONO_ADD_INS (cfg->cbb, ins);
3677         } else {
3678                 int inited_reg;
3679                 MonoBasicBlock *inited_bb;
3680                 MonoInst *args [16];
3681
3682                 inited_reg = alloc_ireg (cfg);
3683
3684                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, inited_reg, vtable_arg->dreg, MONO_STRUCT_OFFSET (MonoVTable, initialized));
3685
3686                 NEW_BBLOCK (cfg, inited_bb);
3687
3688                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3689                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3690
3691                 args [0] = vtable_arg;
3692                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3693
3694                 MONO_START_BB (cfg, inited_bb);
3695         }
3696 }
3697
3698 static void
3699 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3700 {
3701         MonoInst *ins;
3702
3703         if (cfg->gen_seq_points && cfg->method == method) {
3704                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3705                 if (nonempty_stack)
3706                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3707                 MONO_ADD_INS (cfg->cbb, ins);
3708         }
3709 }
3710
3711 void
3712 mini_save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3713 {
3714         if (mini_get_debug_options ()->better_cast_details) {
3715                 int vtable_reg = alloc_preg (cfg);
3716                 int klass_reg = alloc_preg (cfg);
3717                 MonoBasicBlock *is_null_bb = NULL;
3718                 MonoInst *tls_get;
3719                 int to_klass_reg, context_used;
3720
3721                 if (null_check) {
3722                         NEW_BBLOCK (cfg, is_null_bb);
3723
3724                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3725                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3726                 }
3727
3728                 tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
3729                 if (!tls_get) {
3730                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3731                         exit (1);
3732                 }
3733
3734                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3735                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3736
3737                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3738
3739                 context_used = mini_class_check_context_used (cfg, klass);
3740                 if (context_used) {
3741                         MonoInst *class_ins;
3742
3743                         class_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3744                         to_klass_reg = class_ins->dreg;
3745                 } else {
3746                         to_klass_reg = alloc_preg (cfg);
3747                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3748                 }
3749                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3750
3751                 if (null_check)
3752                         MONO_START_BB (cfg, is_null_bb);
3753         }
3754 }
3755
3756 void
3757 mini_reset_cast_details (MonoCompile *cfg)
3758 {
3759         /* Reset the variables holding the cast details */
3760         if (mini_get_debug_options ()->better_cast_details) {
3761                 MonoInst *tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
3762                 /* It is enough to reset the from field */
3763                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3764         }
3765 }
3766
3767 /*
3768  * On return the caller must check @array_class for load errors
3769  */
3770 static void
3771 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3772 {
3773         int vtable_reg = alloc_preg (cfg);
3774         int context_used;
3775
3776         context_used = mini_class_check_context_used (cfg, array_class);
3777
3778         mini_save_cast_details (cfg, array_class, obj->dreg, FALSE);
3779
3780         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3781
3782         if (cfg->opt & MONO_OPT_SHARED) {
3783                 int class_reg = alloc_preg (cfg);
3784                 MonoInst *ins;
3785
3786                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3787                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3788                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3789         } else if (context_used) {
3790                 MonoInst *vtable_ins;
3791
3792                 vtable_ins = mini_emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3793                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3794         } else {
3795                 if (cfg->compile_aot) {
3796                         int vt_reg;
3797                         MonoVTable *vtable;
3798
3799                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3800                                 return;
3801                         vt_reg = alloc_preg (cfg);
3802                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3803                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3804                 } else {
3805                         MonoVTable *vtable;
3806                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3807                                 return;
3808                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3809                 }
3810         }
3811         
3812         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3813
3814         mini_reset_cast_details (cfg);
3815 }
3816
3817 /**
3818  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3819  * generic code is generated.
3820  */
3821 static MonoInst*
3822 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3823 {
3824         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3825
3826         if (context_used) {
3827                 MonoInst *rgctx, *addr;
3828
3829                 /* FIXME: What if the class is shared?  We might not
3830                    have to get the address of the method from the
3831                    RGCTX. */
3832                 addr = emit_get_rgctx_method (cfg, context_used, method,
3833                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3834                 if (cfg->llvm_only) {
3835                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
3836                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
3837                 } else {
3838                         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3839
3840                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3841                 }
3842         } else {
3843                 gboolean pass_vtable, pass_mrgctx;
3844                 MonoInst *rgctx_arg = NULL;
3845
3846                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3847                 g_assert (!pass_mrgctx);
3848
3849                 if (pass_vtable) {
3850                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3851
3852                         g_assert (vtable);
3853                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3854                 }
3855
3856                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3857         }
3858 }
3859
3860 static MonoInst*
3861 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3862 {
3863         MonoInst *add;
3864         int obj_reg;
3865         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3866         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3867         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3868         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3869
3870         obj_reg = sp [0]->dreg;
3871         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3872         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3873
3874         /* FIXME: generics */
3875         g_assert (klass->rank == 0);
3876                         
3877         // Check rank == 0
3878         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3879         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3880
3881         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3882         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3883
3884         if (context_used) {
3885                 MonoInst *element_class;
3886
3887                 /* This assertion is from the unboxcast insn */
3888                 g_assert (klass->rank == 0);
3889
3890                 element_class = mini_emit_get_rgctx_klass (cfg, context_used,
3891                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
3892
3893                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3894                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3895         } else {
3896                 mini_save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
3897                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3898                 mini_reset_cast_details (cfg);
3899         }
3900
3901         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3902         MONO_ADD_INS (cfg->cbb, add);
3903         add->type = STACK_MP;
3904         add->klass = klass;
3905
3906         return add;
3907 }
3908
3909 static MonoInst*
3910 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
3911 {
3912         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3913         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3914         MonoInst *ins;
3915         int dreg, addr_reg;
3916
3917         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3918
3919         /* obj */
3920         args [0] = obj;
3921
3922         /* klass */
3923         args [1] = klass_inst;
3924
3925         /* CASTCLASS */
3926         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3927
3928         NEW_BBLOCK (cfg, is_ref_bb);
3929         NEW_BBLOCK (cfg, is_nullable_bb);
3930         NEW_BBLOCK (cfg, end_bb);
3931         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3932         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
3933         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3934
3935         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
3936         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3937
3938         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3939         addr_reg = alloc_dreg (cfg, STACK_MP);
3940
3941         /* Non-ref case */
3942         /* UNBOX */
3943         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3944         MONO_ADD_INS (cfg->cbb, addr);
3945
3946         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3947
3948         /* Ref case */
3949         MONO_START_BB (cfg, is_ref_bb);
3950
3951         /* Save the ref to a temporary */
3952         dreg = alloc_ireg (cfg);
3953         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3954         addr->dreg = addr_reg;
3955         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3956         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3957
3958         /* Nullable case */
3959         MONO_START_BB (cfg, is_nullable_bb);
3960
3961         {
3962                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3963                 MonoInst *unbox_call;
3964                 MonoMethodSignature *unbox_sig;
3965
3966                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3967                 unbox_sig->ret = &klass->byval_arg;
3968                 unbox_sig->param_count = 1;
3969                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3970
3971                 if (cfg->llvm_only)
3972                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
3973                 else
3974                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3975
3976                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3977                 addr->dreg = addr_reg;
3978         }
3979
3980         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3981
3982         /* End */
3983         MONO_START_BB (cfg, end_bb);
3984
3985         /* LDOBJ */
3986         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3987
3988         return ins;
3989 }
3990
3991 /*
3992  * Returns NULL and set the cfg exception on error.
3993  */
3994 static MonoInst*
3995 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3996 {
3997         MonoInst *iargs [2];
3998         void *alloc_ftn;
3999
4000         if (context_used) {
4001                 MonoInst *data;
4002                 MonoRgctxInfoType rgctx_info;
4003                 MonoInst *iargs [2];
4004                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4005
4006                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4007
4008                 if (cfg->opt & MONO_OPT_SHARED)
4009                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4010                 else
4011                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4012                 data = mini_emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4013
4014                 if (cfg->opt & MONO_OPT_SHARED) {
4015                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4016                         iargs [1] = data;
4017                         alloc_ftn = ves_icall_object_new;
4018                 } else {
4019                         iargs [0] = data;
4020                         alloc_ftn = ves_icall_object_new_specific;
4021                 }
4022
4023                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4024                         if (known_instance_size) {
4025                                 int size = mono_class_instance_size (klass);
4026                                 if (size < sizeof (MonoObject))
4027                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4028
4029                                 EMIT_NEW_ICONST (cfg, iargs [1], size);
4030                         }
4031                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4032                 }
4033
4034                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4035         }
4036
4037         if (cfg->opt & MONO_OPT_SHARED) {
4038                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4039                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4040
4041                 alloc_ftn = ves_icall_object_new;
4042         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !mono_class_is_ginst (klass)) {
4043                 /* This happens often in argument checking code, eg. throw new FooException... */
4044                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4045                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4046                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4047         } else {
4048                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4049                 MonoMethod *managed_alloc = NULL;
4050                 gboolean pass_lw;
4051
4052                 if (!vtable) {
4053                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4054                         cfg->exception_ptr = klass;
4055                         return NULL;
4056                 }
4057
4058                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4059
4060                 if (managed_alloc) {
4061                         int size = mono_class_instance_size (klass);
4062                         if (size < sizeof (MonoObject))
4063                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4064
4065                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4066                         EMIT_NEW_ICONST (cfg, iargs [1], size);
4067                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4068                 }
4069                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4070                 if (pass_lw) {
4071                         guint32 lw = vtable->klass->instance_size;
4072                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4073                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4074                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4075                 }
4076                 else {
4077                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4078                 }
4079         }
4080
4081         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4082 }
4083         
4084 /*
4085  * Returns NULL and set the cfg exception on error.
4086  */     
4087 static MonoInst*
4088 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4089 {
4090         MonoInst *alloc, *ins;
4091
4092         if (mono_class_is_nullable (klass)) {
4093                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4094
4095                 if (context_used) {
4096                         if (cfg->llvm_only && cfg->gsharedvt) {
4097                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4098                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4099                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4100                         } else {
4101                                 /* FIXME: What if the class is shared?  We might not
4102                                    have to get the method address from the RGCTX. */
4103                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4104                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4105                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
4106
4107                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4108                         }
4109                 } else {
4110                         gboolean pass_vtable, pass_mrgctx;
4111                         MonoInst *rgctx_arg = NULL;
4112
4113                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4114                         g_assert (!pass_mrgctx);
4115
4116                         if (pass_vtable) {
4117                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4118
4119                                 g_assert (vtable);
4120                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4121                         }
4122
4123                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4124                 }
4125         }
4126
4127         if (mini_is_gsharedvt_klass (klass)) {
4128                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4129                 MonoInst *res, *is_ref, *src_var, *addr;
4130                 int dreg;
4131
4132                 dreg = alloc_ireg (cfg);
4133
4134                 NEW_BBLOCK (cfg, is_ref_bb);
4135                 NEW_BBLOCK (cfg, is_nullable_bb);
4136                 NEW_BBLOCK (cfg, end_bb);
4137                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4138                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4139                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4140
4141                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4142                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4143
4144                 /* Non-ref case */
4145                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4146                 if (!alloc)
4147                         return NULL;
4148                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4149                 ins->opcode = OP_STOREV_MEMBASE;
4150
4151                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4152                 res->type = STACK_OBJ;
4153                 res->klass = klass;
4154                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4155                 
4156                 /* Ref case */
4157                 MONO_START_BB (cfg, is_ref_bb);
4158
4159                 /* val is a vtype, so has to load the value manually */
4160                 src_var = get_vreg_to_inst (cfg, val->dreg);
4161                 if (!src_var)
4162                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4163                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4164                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4165                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4166
4167                 /* Nullable case */
4168                 MONO_START_BB (cfg, is_nullable_bb);
4169
4170                 {
4171                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4172                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4173                         MonoInst *box_call;
4174                         MonoMethodSignature *box_sig;
4175
4176                         /*
4177                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4178                          * construct that method at JIT time, so have to do things by hand.
4179                          */
4180                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4181                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4182                         box_sig->param_count = 1;
4183                         box_sig->params [0] = &klass->byval_arg;
4184
4185                         if (cfg->llvm_only)
4186                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4187                         else
4188                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4189                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4190                         res->type = STACK_OBJ;
4191                         res->klass = klass;
4192                 }
4193
4194                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4195
4196                 MONO_START_BB (cfg, end_bb);
4197
4198                 return res;
4199         } else {
4200                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4201                 if (!alloc)
4202                         return NULL;
4203
4204                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4205                 return alloc;
4206         }
4207 }
4208
4209 static GHashTable* direct_icall_type_hash;
4210
4211 static gboolean
4212 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4213 {
4214         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4215         if (!direct_icalls_enabled (cfg))
4216                 return FALSE;
4217
4218         /*
4219          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4220          * Whitelist a few icalls for now.
4221          */
4222         if (!direct_icall_type_hash) {
4223                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4224
4225                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4226                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4227                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4228                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4229                 mono_memory_barrier ();
4230                 direct_icall_type_hash = h;
4231         }
4232
4233         if (cmethod->klass == mono_defaults.math_class)
4234                 return TRUE;
4235         /* No locking needed */
4236         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4237                 return TRUE;
4238         return FALSE;
4239 }
4240
4241 static gboolean
4242 method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
4243 {
4244         if (cmethod->klass == mono_defaults.systemtype_class) {
4245                 if (!strcmp (cmethod->name, "GetType"))
4246                         return TRUE;
4247         }
4248         return FALSE;
4249 }
4250
4251 static G_GNUC_UNUSED MonoInst*
4252 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4253 {
4254         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4255         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4256         gboolean is_i4;
4257
4258         switch (enum_type->type) {
4259         case MONO_TYPE_I8:
4260         case MONO_TYPE_U8:
4261 #if SIZEOF_REGISTER == 8
4262         case MONO_TYPE_I:
4263         case MONO_TYPE_U:
4264 #endif
4265                 is_i4 = FALSE;
4266                 break;
4267         default:
4268                 is_i4 = TRUE;
4269                 break;
4270         }
4271
4272         {
4273                 MonoInst *load, *and_, *cmp, *ceq;
4274                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4275                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4276                 int dest_reg = alloc_ireg (cfg);
4277
4278                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4279                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4280                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4281                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4282
4283                 ceq->type = STACK_I4;
4284
4285                 if (!is_i4) {
4286                         load = mono_decompose_opcode (cfg, load);
4287                         and_ = mono_decompose_opcode (cfg, and_);
4288                         cmp = mono_decompose_opcode (cfg, cmp);
4289                         ceq = mono_decompose_opcode (cfg, ceq);
4290                 }
4291
4292                 return ceq;
4293         }
4294 }
4295
4296 /*
4297  * Returns NULL and set the cfg exception on error.
4298  */
4299 static G_GNUC_UNUSED MonoInst*
4300 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
4301 {
4302         MonoInst *ptr;
4303         int dreg;
4304         gpointer trampoline;
4305         MonoInst *obj, *method_ins, *tramp_ins;
4306         MonoDomain *domain;
4307         guint8 **code_slot;
4308
4309         if (virtual_ && !cfg->llvm_only) {
4310                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4311                 g_assert (invoke);
4312
4313                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4314                         return NULL;
4315         }
4316
4317         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
4318         if (!obj)
4319                 return NULL;
4320
4321         /* Inline the contents of mono_delegate_ctor */
4322
4323         /* Set target field */
4324         /* Optimize away setting of NULL target */
4325         if (!MONO_INS_IS_PCONST_NULL (target)) {
4326                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4327                 if (cfg->gen_write_barriers) {
4328                         dreg = alloc_preg (cfg);
4329                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4330                         emit_write_barrier (cfg, ptr, target);
4331                 }
4332         }
4333
4334         /* Set method field */
4335         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4336         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4337
4338         /* 
4339          * To avoid looking up the compiled code belonging to the target method
4340          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4341          * store it, and we fill it after the method has been compiled.
4342          */
4343         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4344                 MonoInst *code_slot_ins;
4345
4346                 if (context_used) {
4347                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4348                 } else {
4349                         domain = mono_domain_get ();
4350                         mono_domain_lock (domain);
4351                         if (!domain_jit_info (domain)->method_code_hash)
4352                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4353                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4354                         if (!code_slot) {
4355                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
4356                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4357                         }
4358                         mono_domain_unlock (domain);
4359
4360                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4361                 }
4362                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4363         }
4364
4365         if (cfg->llvm_only) {
4366                 MonoInst *args [16];
4367
4368                 if (virtual_) {
4369                         args [0] = obj;
4370                         args [1] = target;
4371                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4372                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
4373                 } else {
4374                         args [0] = obj;
4375                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
4376                 }
4377
4378                 return obj;
4379         }
4380
4381         if (cfg->compile_aot) {
4382                 MonoDelegateClassMethodPair *del_tramp;
4383
4384                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4385                 del_tramp->klass = klass;
4386                 del_tramp->method = context_used ? NULL : method;
4387                 del_tramp->is_virtual = virtual_;
4388                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4389         } else {
4390                 if (virtual_)
4391                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4392                 else
4393                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4394                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4395         }
4396
4397         /* Set invoke_impl field */
4398         if (virtual_) {
4399                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4400         } else {
4401                 dreg = alloc_preg (cfg);
4402                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4403                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4404
4405                 dreg = alloc_preg (cfg);
4406                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4407                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4408         }
4409
4410         dreg = alloc_preg (cfg);
4411         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
4412         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
4413
4414         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4415
4416         return obj;
4417 }
4418
4419 static MonoInst*
4420 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4421 {
4422         MonoJitICallInfo *info;
4423
4424         /* Need to register the icall so it gets an icall wrapper */
4425         info = mono_get_array_new_va_icall (rank);
4426
4427         cfg->flags |= MONO_CFG_HAS_VARARGS;
4428
4429         /* mono_array_new_va () needs a vararg calling convention */
4430         cfg->exception_message = g_strdup ("array-new");
4431         cfg->disable_llvm = TRUE;
4432
4433         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4434         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4435 }
4436
4437 /*
4438  * handle_constrained_gsharedvt_call:
4439  *
4440  *   Handle constrained calls where the receiver is a gsharedvt type.
4441  * Return the instruction representing the call. Set the cfg exception on failure.
4442  */
4443 static MonoInst*
4444 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
4445                                                                    gboolean *ref_emit_widen)
4446 {
4447         MonoInst *ins = NULL;
4448         gboolean emit_widen = *ref_emit_widen;
4449
4450         /*
4451          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
4452          * 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
4453          * pack the arguments into an array, and do the rest of the work in in an icall.
4454          */
4455         if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
4456                 (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)) &&
4457                 (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]))))) {
4458                 MonoInst *args [16];
4459
4460                 /*
4461                  * This case handles calls to
4462                  * - object:ToString()/Equals()/GetHashCode(),
4463                  * - System.IComparable<T>:CompareTo()
4464                  * - System.IEquatable<T>:Equals ()
4465                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
4466                  */
4467
4468                 args [0] = sp [0];
4469                 if (mono_method_check_context_used (cmethod))
4470                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
4471                 else
4472                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
4473                 args [2] = mini_emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
4474
4475                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
4476                 if (fsig->hasthis && fsig->param_count) {
4477                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
4478                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
4479                         ins->dreg = alloc_preg (cfg);
4480                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
4481                         MONO_ADD_INS (cfg->cbb, ins);
4482                         args [4] = ins;
4483
4484                         if (mini_is_gsharedvt_type (fsig->params [0])) {
4485                                 int addr_reg, deref_arg_reg;
4486
4487                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4488                                 deref_arg_reg = alloc_preg (cfg);
4489                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
4490                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
4491
4492                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
4493                                 addr_reg = ins->dreg;
4494                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
4495                         } else {
4496                                 EMIT_NEW_ICONST (cfg, args [3], 0);
4497                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
4498                         }
4499                 } else {
4500                         EMIT_NEW_ICONST (cfg, args [3], 0);
4501                         EMIT_NEW_ICONST (cfg, args [4], 0);
4502                 }
4503                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
4504                 emit_widen = FALSE;
4505
4506                 if (mini_is_gsharedvt_type (fsig->ret)) {
4507                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
4508                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mono_class_is_enum (mono_class_from_mono_type (fsig->ret))) {
4509                         MonoInst *add;
4510
4511                         /* Unbox */
4512                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
4513                         MONO_ADD_INS (cfg->cbb, add);
4514                         /* Load value */
4515                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
4516                         MONO_ADD_INS (cfg->cbb, ins);
4517                         /* ins represents the call result */
4518                 }
4519         } else {
4520                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
4521         }
4522
4523         *ref_emit_widen = emit_widen;
4524
4525         return ins;
4526
4527  exception_exit:
4528         return NULL;
4529 }
4530
4531 static void
4532 mono_emit_load_got_addr (MonoCompile *cfg)
4533 {
4534         MonoInst *getaddr, *dummy_use;
4535
4536         if (!cfg->got_var || cfg->got_var_allocated)
4537                 return;
4538
4539         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4540         getaddr->cil_code = cfg->header->code;
4541         getaddr->dreg = cfg->got_var->dreg;
4542
4543         /* Add it to the start of the first bblock */
4544         if (cfg->bb_entry->code) {
4545                 getaddr->next = cfg->bb_entry->code;
4546                 cfg->bb_entry->code = getaddr;
4547         }
4548         else
4549                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4550
4551         cfg->got_var_allocated = TRUE;
4552
4553         /* 
4554          * Add a dummy use to keep the got_var alive, since real uses might
4555          * only be generated by the back ends.
4556          * Add it to end_bblock, so the variable's lifetime covers the whole
4557          * method.
4558          * It would be better to make the usage of the got var explicit in all
4559          * cases when the backend needs it (i.e. calls, throw etc.), so this
4560          * wouldn't be needed.
4561          */
4562         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4563         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4564 }
4565
4566 static int inline_limit;
4567 static gboolean inline_limit_inited;
4568
4569 static gboolean
4570 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4571 {
4572         MonoMethodHeaderSummary header;
4573         MonoVTable *vtable;
4574 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4575         MonoMethodSignature *sig = mono_method_signature (method);
4576         int i;
4577 #endif
4578
4579         if (cfg->disable_inline)
4580                 return FALSE;
4581         if (cfg->gsharedvt)
4582                 return FALSE;
4583
4584         if (cfg->inline_depth > 10)
4585                 return FALSE;
4586
4587         if (!mono_method_get_header_summary (method, &header))
4588                 return FALSE;
4589
4590         /*runtime, icall and pinvoke are checked by summary call*/
4591         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4592             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4593             (mono_class_is_marshalbyref (method->klass)) ||
4594             header.has_clauses)
4595                 return FALSE;
4596
4597         /* also consider num_locals? */
4598         /* Do the size check early to avoid creating vtables */
4599         if (!inline_limit_inited) {
4600                 if (g_getenv ("MONO_INLINELIMIT"))
4601                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4602                 else
4603                         inline_limit = INLINE_LENGTH_LIMIT;
4604                 inline_limit_inited = TRUE;
4605         }
4606         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4607                 return FALSE;
4608
4609         /*
4610          * if we can initialize the class of the method right away, we do,
4611          * otherwise we don't allow inlining if the class needs initialization,
4612          * since it would mean inserting a call to mono_runtime_class_init()
4613          * inside the inlined code
4614          */
4615         if (cfg->gshared && method->klass->has_cctor && mini_class_check_context_used (cfg, method->klass))
4616                 return FALSE;
4617
4618         if (!(cfg->opt & MONO_OPT_SHARED)) {
4619                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4620                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4621                         if (method->klass->has_cctor) {
4622                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4623                                 if (!vtable)
4624                                         return FALSE;
4625                                 if (!cfg->compile_aot) {
4626                                         MonoError error;
4627                                         if (!mono_runtime_class_init_full (vtable, &error)) {
4628                                                 mono_error_cleanup (&error);
4629                                                 return FALSE;
4630                                         }
4631                                 }
4632                         }
4633                 } else if (mono_class_is_before_field_init (method->klass)) {
4634                         if (cfg->run_cctors && method->klass->has_cctor) {
4635                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4636                                 if (!method->klass->runtime_info)
4637                                         /* No vtable created yet */
4638                                         return FALSE;
4639                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4640                                 if (!vtable)
4641                                         return FALSE;
4642                                 /* This makes so that inline cannot trigger */
4643                                 /* .cctors: too many apps depend on them */
4644                                 /* running with a specific order... */
4645                                 if (! vtable->initialized)
4646                                         return FALSE;
4647                                 MonoError error;
4648                                 if (!mono_runtime_class_init_full (vtable, &error)) {
4649                                         mono_error_cleanup (&error);
4650                                         return FALSE;
4651                                 }
4652                         }
4653                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4654                         if (!method->klass->runtime_info)
4655                                 /* No vtable created yet */
4656                                 return FALSE;
4657                         vtable = mono_class_vtable (cfg->domain, method->klass);
4658                         if (!vtable)
4659                                 return FALSE;
4660                         if (!vtable->initialized)
4661                                 return FALSE;
4662                 }
4663         } else {
4664                 /* 
4665                  * If we're compiling for shared code
4666                  * the cctor will need to be run at aot method load time, for example,
4667                  * or at the end of the compilation of the inlining method.
4668                  */
4669                 if (mono_class_needs_cctor_run (method->klass, NULL) && !mono_class_is_before_field_init (method->klass))
4670                         return FALSE;
4671         }
4672
4673 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4674         if (mono_arch_is_soft_float ()) {
4675                 /* FIXME: */
4676                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4677                         return FALSE;
4678                 for (i = 0; i < sig->param_count; ++i)
4679                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4680                                 return FALSE;
4681         }
4682 #endif
4683
4684         if (g_list_find (cfg->dont_inline, method))
4685                 return FALSE;
4686
4687         return TRUE;
4688 }
4689
4690 static gboolean
4691 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4692 {
4693         if (!cfg->compile_aot) {
4694                 g_assert (vtable);
4695                 if (vtable->initialized)
4696                         return FALSE;
4697         }
4698
4699         if (mono_class_is_before_field_init (klass)) {
4700                 if (cfg->method == method)
4701                         return FALSE;
4702         }
4703
4704         if (!mono_class_needs_cctor_run (klass, method))
4705                 return FALSE;
4706
4707         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4708                 /* The initialization is already done before the method is called */
4709                 return FALSE;
4710
4711         return TRUE;
4712 }
4713
4714 MonoInst*
4715 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4716 {
4717         MonoInst *ins;
4718         guint32 size;
4719         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4720         int context_used;
4721
4722         if (mini_is_gsharedvt_variable_klass (klass)) {
4723                 size = -1;
4724         } else {
4725                 mono_class_init (klass);
4726                 size = mono_class_array_element_size (klass);
4727         }
4728
4729         mult_reg = alloc_preg (cfg);
4730         array_reg = arr->dreg;
4731         index_reg = index->dreg;
4732
4733 #if SIZEOF_REGISTER == 8
4734         /* The array reg is 64 bits but the index reg is only 32 */
4735         if (COMPILE_LLVM (cfg)) {
4736                 /* Not needed */
4737                 index2_reg = index_reg;
4738         } else {
4739                 index2_reg = alloc_preg (cfg);
4740                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4741         }
4742 #else
4743         if (index->type == STACK_I8) {
4744                 index2_reg = alloc_preg (cfg);
4745                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4746         } else {
4747                 index2_reg = index_reg;
4748         }
4749 #endif
4750
4751         if (bcheck)
4752                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4753
4754 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4755         if (size == 1 || size == 2 || size == 4 || size == 8) {
4756                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4757
4758                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
4759                 ins->klass = mono_class_get_element_class (klass);
4760                 ins->type = STACK_MP;
4761
4762                 return ins;
4763         }
4764 #endif          
4765
4766         add_reg = alloc_ireg_mp (cfg);
4767
4768         if (size == -1) {
4769                 MonoInst *rgctx_ins;
4770
4771                 /* gsharedvt */
4772                 g_assert (cfg->gshared);
4773                 context_used = mini_class_check_context_used (cfg, klass);
4774                 g_assert (context_used);
4775                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4776                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4777         } else {
4778                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4779         }
4780         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4781         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4782         ins->klass = mono_class_get_element_class (klass);
4783         ins->type = STACK_MP;
4784         MONO_ADD_INS (cfg->cbb, ins);
4785
4786         return ins;
4787 }
4788
4789 static MonoInst*
4790 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4791 {
4792         int bounds_reg = alloc_preg (cfg);
4793         int add_reg = alloc_ireg_mp (cfg);
4794         int mult_reg = alloc_preg (cfg);
4795         int mult2_reg = alloc_preg (cfg);
4796         int low1_reg = alloc_preg (cfg);
4797         int low2_reg = alloc_preg (cfg);
4798         int high1_reg = alloc_preg (cfg);
4799         int high2_reg = alloc_preg (cfg);
4800         int realidx1_reg = alloc_preg (cfg);
4801         int realidx2_reg = alloc_preg (cfg);
4802         int sum_reg = alloc_preg (cfg);
4803         int index1, index2, tmpreg;
4804         MonoInst *ins;
4805         guint32 size;
4806
4807         mono_class_init (klass);
4808         size = mono_class_array_element_size (klass);
4809
4810         index1 = index_ins1->dreg;
4811         index2 = index_ins2->dreg;
4812
4813 #if SIZEOF_REGISTER == 8
4814         /* The array reg is 64 bits but the index reg is only 32 */
4815         if (COMPILE_LLVM (cfg)) {
4816                 /* Not needed */
4817         } else {
4818                 tmpreg = alloc_preg (cfg);
4819                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4820                 index1 = tmpreg;
4821                 tmpreg = alloc_preg (cfg);
4822                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4823                 index2 = tmpreg;
4824         }
4825 #else
4826         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4827         tmpreg = -1;
4828 #endif
4829
4830         /* range checking */
4831         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4832                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4833
4834         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4835                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4836         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4837         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4838                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4839         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4840         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4841
4842         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4843                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4844         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4845         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4846                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4847         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4848         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4849
4850         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4851         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4852         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4853         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4854         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4855
4856         ins->type = STACK_MP;
4857         ins->klass = klass;
4858         MONO_ADD_INS (cfg->cbb, ins);
4859
4860         return ins;
4861 }
4862
4863 static MonoInst*
4864 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4865 {
4866         int rank;
4867         MonoInst *addr;
4868         MonoMethod *addr_method;
4869         int element_size;
4870         MonoClass *eclass = cmethod->klass->element_class;
4871
4872         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4873
4874         if (rank == 1)
4875                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
4876
4877         /* emit_ldelema_2 depends on OP_LMUL */
4878         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
4879                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
4880         }
4881
4882         if (mini_is_gsharedvt_variable_klass (eclass))
4883                 element_size = 0;
4884         else
4885                 element_size = mono_class_array_element_size (eclass);
4886         addr_method = mono_marshal_get_array_address (rank, element_size);
4887         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4888
4889         return addr;
4890 }
4891
4892 static MonoBreakPolicy
4893 always_insert_breakpoint (MonoMethod *method)
4894 {
4895         return MONO_BREAK_POLICY_ALWAYS;
4896 }
4897
4898 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4899
4900 /**
4901  * mono_set_break_policy:
4902  * policy_callback: the new callback function
4903  *
4904  * Allow embedders to decide wherther to actually obey breakpoint instructions
4905  * (both break IL instructions and Debugger.Break () method calls), for example
4906  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4907  * untrusted or semi-trusted code.
4908  *
4909  * @policy_callback will be called every time a break point instruction needs to
4910  * be inserted with the method argument being the method that calls Debugger.Break()
4911  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4912  * if it wants the breakpoint to not be effective in the given method.
4913  * #MONO_BREAK_POLICY_ALWAYS is the default.
4914  */
4915 void
4916 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4917 {
4918         if (policy_callback)
4919                 break_policy_func = policy_callback;
4920         else
4921                 break_policy_func = always_insert_breakpoint;
4922 }
4923
4924 static gboolean
4925 should_insert_brekpoint (MonoMethod *method) {
4926         switch (break_policy_func (method)) {
4927         case MONO_BREAK_POLICY_ALWAYS:
4928                 return TRUE;
4929         case MONO_BREAK_POLICY_NEVER:
4930                 return FALSE;
4931         case MONO_BREAK_POLICY_ON_DBG:
4932                 g_warning ("mdb no longer supported");
4933                 return FALSE;
4934         default:
4935                 g_warning ("Incorrect value returned from break policy callback");
4936                 return FALSE;
4937         }
4938 }
4939
4940 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4941 static MonoInst*
4942 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4943 {
4944         MonoInst *addr, *store, *load;
4945         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4946
4947         /* the bounds check is already done by the callers */
4948         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4949         if (is_set) {
4950                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4951                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4952                 if (mini_type_is_reference (&eklass->byval_arg))
4953                         emit_write_barrier (cfg, addr, load);
4954         } else {
4955                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4956                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4957         }
4958         return store;
4959 }
4960
4961
4962 static gboolean
4963 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4964 {
4965         return mini_type_is_reference (&klass->byval_arg);
4966 }
4967
4968 static MonoInst*
4969 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
4970 {
4971         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
4972                 !(MONO_INS_IS_PCONST_NULL (sp [2]))) {
4973                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
4974                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
4975                 MonoInst *iargs [3];
4976
4977                 if (!helper->slot)
4978                         mono_class_setup_vtable (obj_array);
4979                 g_assert (helper->slot);
4980
4981                 if (sp [0]->type != STACK_OBJ)
4982                         return NULL;
4983                 if (sp [2]->type != STACK_OBJ)
4984                         return NULL;
4985
4986                 iargs [2] = sp [2];
4987                 iargs [1] = sp [1];
4988                 iargs [0] = sp [0];
4989
4990                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
4991         } else {
4992                 MonoInst *ins;
4993
4994                 if (mini_is_gsharedvt_variable_klass (klass)) {
4995                         MonoInst *addr;
4996
4997                         // FIXME-VT: OP_ICONST optimization
4998                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
4999                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5000                         ins->opcode = OP_STOREV_MEMBASE;
5001                 } else if (sp [1]->opcode == OP_ICONST) {
5002                         int array_reg = sp [0]->dreg;
5003                         int index_reg = sp [1]->dreg;
5004                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5005
5006                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5007                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5008
5009                         if (safety_checks)
5010                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5011                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5012                 } else {
5013                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5014                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5015                         if (generic_class_is_reference_type (cfg, klass))
5016                                 emit_write_barrier (cfg, addr, sp [2]);
5017                 }
5018                 return ins;
5019         }
5020 }
5021
5022 static MonoInst*
5023 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5024 {
5025         MonoClass *eklass;
5026         
5027         if (is_set)
5028                 eklass = mono_class_from_mono_type (fsig->params [2]);
5029         else
5030                 eklass = mono_class_from_mono_type (fsig->ret);
5031
5032         if (is_set) {
5033                 return emit_array_store (cfg, eklass, args, FALSE);
5034         } else {
5035                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5036                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5037                 return ins;
5038         }
5039 }
5040
5041 static gboolean
5042 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5043 {
5044         uint32_t align;
5045         int param_size, return_size;
5046
5047         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5048         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5049
5050         if (cfg->verbose_level > 3)
5051                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5052
5053         //Don't allow mixing reference types with value types
5054         if (param_klass->valuetype != return_klass->valuetype) {
5055                 if (cfg->verbose_level > 3)
5056                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5057                 return FALSE;
5058         }
5059
5060         if (!param_klass->valuetype) {
5061                 if (cfg->verbose_level > 3)
5062                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5063                 return TRUE;
5064         }
5065
5066         //That are blitable
5067         if (param_klass->has_references || return_klass->has_references)
5068                 return FALSE;
5069
5070         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5071         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5072                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5073                         if (cfg->verbose_level > 3)
5074                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5075                 return FALSE;
5076         }
5077
5078         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5079                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5080                 if (cfg->verbose_level > 3)
5081                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5082                 return FALSE;
5083         }
5084
5085         param_size = mono_class_value_size (param_klass, &align);
5086         return_size = mono_class_value_size (return_klass, &align);
5087
5088         //We can do it if sizes match
5089         if (param_size == return_size) {
5090                 if (cfg->verbose_level > 3)
5091                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5092                 return TRUE;
5093         }
5094
5095         //No simple way to handle struct if sizes don't match
5096         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5097                 if (cfg->verbose_level > 3)
5098                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5099                 return FALSE;
5100         }
5101
5102         /*
5103          * Same reg size category.
5104          * A quick note on why we don't require widening here.
5105          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5106          *
5107          * Since the source value comes from a function argument, the JIT will already have
5108          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5109          */
5110         if (param_size <= 4 && return_size <= 4) {
5111                 if (cfg->verbose_level > 3)
5112                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5113                 return TRUE;
5114         }
5115
5116         return FALSE;
5117 }
5118
5119 static MonoInst*
5120 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5121 {
5122         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5123         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5124
5125         if (mini_is_gsharedvt_variable_type (fsig->ret))
5126                 return NULL;
5127
5128         //Valuetypes that are semantically equivalent or numbers than can be widened to
5129         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5130                 return args [0];
5131
5132         //Arrays of valuetypes that are semantically equivalent
5133         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5134                 return args [0];
5135
5136         return NULL;
5137 }
5138
5139 static MonoInst*
5140 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5141 {
5142 #ifdef MONO_ARCH_SIMD_INTRINSICS
5143         MonoInst *ins = NULL;
5144
5145         if (cfg->opt & MONO_OPT_SIMD) {
5146                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5147                 if (ins)
5148                         return ins;
5149         }
5150 #endif
5151
5152         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5153 }
5154
5155 static MonoInst*
5156 emit_memory_barrier (MonoCompile *cfg, int kind)
5157 {
5158         MonoInst *ins = NULL;
5159         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5160         MONO_ADD_INS (cfg->cbb, ins);
5161         ins->backend.memory_barrier_kind = kind;
5162
5163         return ins;
5164 }
5165
5166 static MonoInst*
5167 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5168 {
5169         MonoInst *ins = NULL;
5170         int opcode = 0;
5171
5172         /* The LLVM backend supports these intrinsics */
5173         if (cmethod->klass == mono_defaults.math_class) {
5174                 if (strcmp (cmethod->name, "Sin") == 0) {
5175                         opcode = OP_SIN;
5176                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5177                         opcode = OP_COS;
5178                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5179                         opcode = OP_SQRT;
5180                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5181                         opcode = OP_ABS;
5182                 }
5183
5184                 if (opcode && fsig->param_count == 1) {
5185                         MONO_INST_NEW (cfg, ins, opcode);
5186                         ins->type = STACK_R8;
5187                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5188                         ins->sreg1 = args [0]->dreg;
5189                         MONO_ADD_INS (cfg->cbb, ins);
5190                 }
5191
5192                 opcode = 0;
5193                 if (cfg->opt & MONO_OPT_CMOV) {
5194                         if (strcmp (cmethod->name, "Min") == 0) {
5195                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5196                                         opcode = OP_IMIN;
5197                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5198                                         opcode = OP_IMIN_UN;
5199                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5200                                         opcode = OP_LMIN;
5201                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5202                                         opcode = OP_LMIN_UN;
5203                         } else if (strcmp (cmethod->name, "Max") == 0) {
5204                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5205                                         opcode = OP_IMAX;
5206                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5207                                         opcode = OP_IMAX_UN;
5208                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5209                                         opcode = OP_LMAX;
5210                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5211                                         opcode = OP_LMAX_UN;
5212                         }
5213                 }
5214
5215                 if (opcode && fsig->param_count == 2) {
5216                         MONO_INST_NEW (cfg, ins, opcode);
5217                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5218                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5219                         ins->sreg1 = args [0]->dreg;
5220                         ins->sreg2 = args [1]->dreg;
5221                         MONO_ADD_INS (cfg->cbb, ins);
5222                 }
5223         }
5224
5225         return ins;
5226 }
5227
5228 static MonoInst*
5229 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5230 {
5231         if (cmethod->klass == mono_defaults.array_class) {
5232                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5233                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5234                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5235                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5236                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5237                         return emit_array_unsafe_mov (cfg, fsig, args);
5238         }
5239
5240         return NULL;
5241 }
5242
5243 static MonoInst*
5244 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5245 {
5246         MonoInst *ins = NULL;
5247
5248          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5249
5250         if (cmethod->klass == mono_defaults.string_class) {
5251                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5252                         int dreg = alloc_ireg (cfg);
5253                         int index_reg = alloc_preg (cfg);
5254                         int add_reg = alloc_preg (cfg);
5255
5256 #if SIZEOF_REGISTER == 8
5257                         if (COMPILE_LLVM (cfg)) {
5258                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5259                         } else {
5260                                 /* The array reg is 64 bits but the index reg is only 32 */
5261                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5262                         }
5263 #else
5264                         index_reg = args [1]->dreg;
5265 #endif  
5266                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5267
5268 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5269                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5270                         add_reg = ins->dreg;
5271                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5272                                                                    add_reg, 0);
5273 #else
5274                         int mult_reg = alloc_preg (cfg);
5275                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5276                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5277                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5278                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5279 #endif
5280                         type_from_op (cfg, ins, NULL, NULL);
5281                         return ins;
5282                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5283                         int dreg = alloc_ireg (cfg);
5284                         /* Decompose later to allow more optimizations */
5285                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5286                         ins->type = STACK_I4;
5287                         ins->flags |= MONO_INST_FAULT;
5288                         cfg->cbb->has_array_access = TRUE;
5289                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5290
5291                         return ins;
5292                 } else 
5293                         return NULL;
5294         } else if (cmethod->klass == mono_defaults.object_class) {
5295                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5296                         int dreg = alloc_ireg_ref (cfg);
5297                         int vt_reg = alloc_preg (cfg);
5298                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5299                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5300                         type_from_op (cfg, ins, NULL, NULL);
5301
5302                         return ins;
5303                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5304                         int dreg = alloc_ireg (cfg);
5305                         int t1 = alloc_ireg (cfg);
5306         
5307                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5308                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5309                         ins->type = STACK_I4;
5310
5311                         return ins;
5312                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5313                         MONO_INST_NEW (cfg, ins, OP_NOP);
5314                         MONO_ADD_INS (cfg->cbb, ins);
5315                         return ins;
5316                 } else
5317                         return NULL;
5318         } else if (cmethod->klass == mono_defaults.array_class) {
5319                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5320                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5321                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5322                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5323
5324 #ifndef MONO_BIG_ARRAYS
5325                 /*
5326                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5327                  * Array methods.
5328                  */
5329                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5330                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5331                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5332                         int dreg = alloc_ireg (cfg);
5333                         int bounds_reg = alloc_ireg_mp (cfg);
5334                         MonoBasicBlock *end_bb, *szarray_bb;
5335                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5336
5337                         NEW_BBLOCK (cfg, end_bb);
5338                         NEW_BBLOCK (cfg, szarray_bb);
5339
5340                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5341                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5342                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5343                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5344                         /* Non-szarray case */
5345                         if (get_length)
5346                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5347                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5348                         else
5349                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5350                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5351                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5352                         MONO_START_BB (cfg, szarray_bb);
5353                         /* Szarray case */
5354                         if (get_length)
5355                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5356                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5357                         else
5358                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5359                         MONO_START_BB (cfg, end_bb);
5360
5361                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5362                         ins->type = STACK_I4;
5363                         
5364                         return ins;
5365                 }
5366 #endif
5367
5368                 if (cmethod->name [0] != 'g')
5369                         return NULL;
5370
5371                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5372                         int dreg = alloc_ireg (cfg);
5373                         int vtable_reg = alloc_preg (cfg);
5374                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5375                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5376                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5377                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5378                         type_from_op (cfg, ins, NULL, NULL);
5379
5380                         return ins;
5381                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5382                         int dreg = alloc_ireg (cfg);
5383
5384                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5385                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5386                         type_from_op (cfg, ins, NULL, NULL);
5387
5388                         return ins;
5389                 } else
5390                         return NULL;
5391         } else if (cmethod->klass == runtime_helpers_class) {
5392                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5393                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5394                         return ins;
5395                 } else
5396                         return NULL;
5397         } else if (cmethod->klass == mono_defaults.monitor_class) {
5398                 gboolean is_enter = FALSE;
5399                 gboolean is_v4 = FALSE;
5400
5401                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 2 && fsig->params [1]->byref) {
5402                         is_enter = TRUE;
5403                         is_v4 = TRUE;
5404                 }
5405                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 1)
5406                         is_enter = TRUE;
5407
5408                 if (is_enter) {
5409                         /*
5410                          * To make async stack traces work, icalls which can block should have a wrapper.
5411                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
5412                          */
5413                         MonoBasicBlock *end_bb;
5414
5415                         NEW_BBLOCK (cfg, end_bb);
5416
5417                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
5418                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
5419                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
5420                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_internal : (gpointer)mono_monitor_enter_internal, args);
5421                         MONO_START_BB (cfg, end_bb);
5422                         return ins;
5423                 }
5424         } else if (cmethod->klass == mono_defaults.thread_class) {
5425                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5426                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5427                         MONO_ADD_INS (cfg->cbb, ins);
5428                         return ins;
5429                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5430                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5431                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5432                         guint32 opcode = 0;
5433                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5434
5435                         if (fsig->params [0]->type == MONO_TYPE_I1)
5436                                 opcode = OP_LOADI1_MEMBASE;
5437                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5438                                 opcode = OP_LOADU1_MEMBASE;
5439                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5440                                 opcode = OP_LOADI2_MEMBASE;
5441                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5442                                 opcode = OP_LOADU2_MEMBASE;
5443                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5444                                 opcode = OP_LOADI4_MEMBASE;
5445                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5446                                 opcode = OP_LOADU4_MEMBASE;
5447                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5448                                 opcode = OP_LOADI8_MEMBASE;
5449                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5450                                 opcode = OP_LOADR4_MEMBASE;
5451                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5452                                 opcode = OP_LOADR8_MEMBASE;
5453                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5454                                 opcode = OP_LOAD_MEMBASE;
5455
5456                         if (opcode) {
5457                                 MONO_INST_NEW (cfg, ins, opcode);
5458                                 ins->inst_basereg = args [0]->dreg;
5459                                 ins->inst_offset = 0;
5460                                 MONO_ADD_INS (cfg->cbb, ins);
5461
5462                                 switch (fsig->params [0]->type) {
5463                                 case MONO_TYPE_I1:
5464                                 case MONO_TYPE_U1:
5465                                 case MONO_TYPE_I2:
5466                                 case MONO_TYPE_U2:
5467                                 case MONO_TYPE_I4:
5468                                 case MONO_TYPE_U4:
5469                                         ins->dreg = mono_alloc_ireg (cfg);
5470                                         ins->type = STACK_I4;
5471                                         break;
5472                                 case MONO_TYPE_I8:
5473                                 case MONO_TYPE_U8:
5474                                         ins->dreg = mono_alloc_lreg (cfg);
5475                                         ins->type = STACK_I8;
5476                                         break;
5477                                 case MONO_TYPE_I:
5478                                 case MONO_TYPE_U:
5479                                         ins->dreg = mono_alloc_ireg (cfg);
5480 #if SIZEOF_REGISTER == 8
5481                                         ins->type = STACK_I8;
5482 #else
5483                                         ins->type = STACK_I4;
5484 #endif
5485                                         break;
5486                                 case MONO_TYPE_R4:
5487                                 case MONO_TYPE_R8:
5488                                         ins->dreg = mono_alloc_freg (cfg);
5489                                         ins->type = STACK_R8;
5490                                         break;
5491                                 default:
5492                                         g_assert (mini_type_is_reference (fsig->params [0]));
5493                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5494                                         ins->type = STACK_OBJ;
5495                                         break;
5496                                 }
5497
5498                                 if (opcode == OP_LOADI8_MEMBASE)
5499                                         ins = mono_decompose_opcode (cfg, ins);
5500
5501                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5502
5503                                 return ins;
5504                         }
5505                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5506                         guint32 opcode = 0;
5507                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5508
5509                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5510                                 opcode = OP_STOREI1_MEMBASE_REG;
5511                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5512                                 opcode = OP_STOREI2_MEMBASE_REG;
5513                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5514                                 opcode = OP_STOREI4_MEMBASE_REG;
5515                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5516                                 opcode = OP_STOREI8_MEMBASE_REG;
5517                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5518                                 opcode = OP_STORER4_MEMBASE_REG;
5519                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5520                                 opcode = OP_STORER8_MEMBASE_REG;
5521                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5522                                 opcode = OP_STORE_MEMBASE_REG;
5523
5524                         if (opcode) {
5525                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5526
5527                                 MONO_INST_NEW (cfg, ins, opcode);
5528                                 ins->sreg1 = args [1]->dreg;
5529                                 ins->inst_destbasereg = args [0]->dreg;
5530                                 ins->inst_offset = 0;
5531                                 MONO_ADD_INS (cfg->cbb, ins);
5532
5533                                 if (opcode == OP_STOREI8_MEMBASE_REG)
5534                                         ins = mono_decompose_opcode (cfg, ins);
5535
5536                                 return ins;
5537                         }
5538                 }
5539         } else if (cmethod->klass->image == mono_defaults.corlib &&
5540                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5541                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5542                 ins = NULL;
5543
5544 #if SIZEOF_REGISTER == 8
5545                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5546                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
5547                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
5548                                 ins->dreg = mono_alloc_preg (cfg);
5549                                 ins->sreg1 = args [0]->dreg;
5550                                 ins->type = STACK_I8;
5551                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
5552                                 MONO_ADD_INS (cfg->cbb, ins);
5553                         } else {
5554                                 MonoInst *load_ins;
5555
5556                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5557
5558                                 /* 64 bit reads are already atomic */
5559                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
5560                                 load_ins->dreg = mono_alloc_preg (cfg);
5561                                 load_ins->inst_basereg = args [0]->dreg;
5562                                 load_ins->inst_offset = 0;
5563                                 load_ins->type = STACK_I8;
5564                                 MONO_ADD_INS (cfg->cbb, load_ins);
5565
5566                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5567
5568                                 ins = load_ins;
5569                         }
5570                 }
5571 #endif
5572
5573                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
5574                         MonoInst *ins_iconst;
5575                         guint32 opcode = 0;
5576
5577                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5578                                 opcode = OP_ATOMIC_ADD_I4;
5579                                 cfg->has_atomic_add_i4 = TRUE;
5580                         }
5581 #if SIZEOF_REGISTER == 8
5582                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5583                                 opcode = OP_ATOMIC_ADD_I8;
5584 #endif
5585                         if (opcode) {
5586                                 if (!mono_arch_opcode_supported (opcode))
5587                                         return NULL;
5588                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5589                                 ins_iconst->inst_c0 = 1;
5590                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5591                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5592
5593                                 MONO_INST_NEW (cfg, ins, opcode);
5594                                 ins->dreg = mono_alloc_ireg (cfg);
5595                                 ins->inst_basereg = args [0]->dreg;
5596                                 ins->inst_offset = 0;
5597                                 ins->sreg2 = ins_iconst->dreg;
5598                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5599                                 MONO_ADD_INS (cfg->cbb, ins);
5600                         }
5601                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
5602                         MonoInst *ins_iconst;
5603                         guint32 opcode = 0;
5604
5605                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5606                                 opcode = OP_ATOMIC_ADD_I4;
5607                                 cfg->has_atomic_add_i4 = TRUE;
5608                         }
5609 #if SIZEOF_REGISTER == 8
5610                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5611                                 opcode = OP_ATOMIC_ADD_I8;
5612 #endif
5613                         if (opcode) {
5614                                 if (!mono_arch_opcode_supported (opcode))
5615                                         return NULL;
5616                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5617                                 ins_iconst->inst_c0 = -1;
5618                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5619                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5620
5621                                 MONO_INST_NEW (cfg, ins, opcode);
5622                                 ins->dreg = mono_alloc_ireg (cfg);
5623                                 ins->inst_basereg = args [0]->dreg;
5624                                 ins->inst_offset = 0;
5625                                 ins->sreg2 = ins_iconst->dreg;
5626                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5627                                 MONO_ADD_INS (cfg->cbb, ins);
5628                         }
5629                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
5630                         guint32 opcode = 0;
5631
5632                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5633                                 opcode = OP_ATOMIC_ADD_I4;
5634                                 cfg->has_atomic_add_i4 = TRUE;
5635                         }
5636 #if SIZEOF_REGISTER == 8
5637                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5638                                 opcode = OP_ATOMIC_ADD_I8;
5639 #endif
5640                         if (opcode) {
5641                                 if (!mono_arch_opcode_supported (opcode))
5642                                         return NULL;
5643                                 MONO_INST_NEW (cfg, ins, opcode);
5644                                 ins->dreg = mono_alloc_ireg (cfg);
5645                                 ins->inst_basereg = args [0]->dreg;
5646                                 ins->inst_offset = 0;
5647                                 ins->sreg2 = args [1]->dreg;
5648                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5649                                 MONO_ADD_INS (cfg->cbb, ins);
5650                         }
5651                 }
5652                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
5653                         MonoInst *f2i = NULL, *i2f;
5654                         guint32 opcode, f2i_opcode, i2f_opcode;
5655                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5656                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
5657
5658                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
5659                             fsig->params [0]->type == MONO_TYPE_R4) {
5660                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5661                                 f2i_opcode = OP_MOVE_F_TO_I4;
5662                                 i2f_opcode = OP_MOVE_I4_TO_F;
5663                                 cfg->has_atomic_exchange_i4 = TRUE;
5664                         }
5665 #if SIZEOF_REGISTER == 8
5666                         else if (is_ref ||
5667                                  fsig->params [0]->type == MONO_TYPE_I8 ||
5668                                  fsig->params [0]->type == MONO_TYPE_R8 ||
5669                                  fsig->params [0]->type == MONO_TYPE_I) {
5670                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5671                                 f2i_opcode = OP_MOVE_F_TO_I8;
5672                                 i2f_opcode = OP_MOVE_I8_TO_F;
5673                         }
5674 #else
5675                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
5676                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5677                                 cfg->has_atomic_exchange_i4 = TRUE;
5678                         }
5679 #endif
5680                         else
5681                                 return NULL;
5682
5683                         if (!mono_arch_opcode_supported (opcode))
5684                                 return NULL;
5685
5686                         if (is_float) {
5687                                 /* TODO: Decompose these opcodes instead of bailing here. */
5688                                 if (COMPILE_SOFT_FLOAT (cfg))
5689                                         return NULL;
5690
5691                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
5692                                 f2i->dreg = mono_alloc_ireg (cfg);
5693                                 f2i->sreg1 = args [1]->dreg;
5694                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5695                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5696                                 MONO_ADD_INS (cfg->cbb, f2i);
5697                         }
5698
5699                         MONO_INST_NEW (cfg, ins, opcode);
5700                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5701                         ins->inst_basereg = args [0]->dreg;
5702                         ins->inst_offset = 0;
5703                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
5704                         MONO_ADD_INS (cfg->cbb, ins);
5705
5706                         switch (fsig->params [0]->type) {
5707                         case MONO_TYPE_I4:
5708                                 ins->type = STACK_I4;
5709                                 break;
5710                         case MONO_TYPE_I8:
5711                                 ins->type = STACK_I8;
5712                                 break;
5713                         case MONO_TYPE_I:
5714 #if SIZEOF_REGISTER == 8
5715                                 ins->type = STACK_I8;
5716 #else
5717                                 ins->type = STACK_I4;
5718 #endif
5719                                 break;
5720                         case MONO_TYPE_R4:
5721                         case MONO_TYPE_R8:
5722                                 ins->type = STACK_R8;
5723                                 break;
5724                         default:
5725                                 g_assert (mini_type_is_reference (fsig->params [0]));
5726                                 ins->type = STACK_OBJ;
5727                                 break;
5728                         }
5729
5730                         if (is_float) {
5731                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5732                                 i2f->dreg = mono_alloc_freg (cfg);
5733                                 i2f->sreg1 = ins->dreg;
5734                                 i2f->type = STACK_R8;
5735                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5736                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5737                                 MONO_ADD_INS (cfg->cbb, i2f);
5738
5739                                 ins = i2f;
5740                         }
5741
5742                         if (cfg->gen_write_barriers && is_ref)
5743                                 emit_write_barrier (cfg, args [0], args [1]);
5744                 }
5745                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
5746                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
5747                         guint32 opcode, f2i_opcode, i2f_opcode;
5748                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
5749                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
5750
5751                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
5752                             fsig->params [1]->type == MONO_TYPE_R4) {
5753                                 opcode = OP_ATOMIC_CAS_I4;
5754                                 f2i_opcode = OP_MOVE_F_TO_I4;
5755                                 i2f_opcode = OP_MOVE_I4_TO_F;
5756                                 cfg->has_atomic_cas_i4 = TRUE;
5757                         }
5758 #if SIZEOF_REGISTER == 8
5759                         else if (is_ref ||
5760                                  fsig->params [1]->type == MONO_TYPE_I8 ||
5761                                  fsig->params [1]->type == MONO_TYPE_R8 ||
5762                                  fsig->params [1]->type == MONO_TYPE_I) {
5763                                 opcode = OP_ATOMIC_CAS_I8;
5764                                 f2i_opcode = OP_MOVE_F_TO_I8;
5765                                 i2f_opcode = OP_MOVE_I8_TO_F;
5766                         }
5767 #else
5768                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
5769                                 opcode = OP_ATOMIC_CAS_I4;
5770                                 cfg->has_atomic_cas_i4 = TRUE;
5771                         }
5772 #endif
5773                         else
5774                                 return NULL;
5775
5776                         if (!mono_arch_opcode_supported (opcode))
5777                                 return NULL;
5778
5779                         if (is_float) {
5780                                 /* TODO: Decompose these opcodes instead of bailing here. */
5781                                 if (COMPILE_SOFT_FLOAT (cfg))
5782                                         return NULL;
5783
5784                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
5785                                 f2i_new->dreg = mono_alloc_ireg (cfg);
5786                                 f2i_new->sreg1 = args [1]->dreg;
5787                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5788                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5789                                 MONO_ADD_INS (cfg->cbb, f2i_new);
5790
5791                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
5792                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
5793                                 f2i_cmp->sreg1 = args [2]->dreg;
5794                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5795                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5796                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
5797                         }
5798
5799                         MONO_INST_NEW (cfg, ins, opcode);
5800                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5801                         ins->sreg1 = args [0]->dreg;
5802                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
5803                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
5804                         MONO_ADD_INS (cfg->cbb, ins);
5805
5806                         switch (fsig->params [1]->type) {
5807                         case MONO_TYPE_I4:
5808                                 ins->type = STACK_I4;
5809                                 break;
5810                         case MONO_TYPE_I8:
5811                                 ins->type = STACK_I8;
5812                                 break;
5813                         case MONO_TYPE_I:
5814 #if SIZEOF_REGISTER == 8
5815                                 ins->type = STACK_I8;
5816 #else
5817                                 ins->type = STACK_I4;
5818 #endif
5819                                 break;
5820                         case MONO_TYPE_R4:
5821                                 ins->type = cfg->r4_stack_type;
5822                                 break;
5823                         case MONO_TYPE_R8:
5824                                 ins->type = STACK_R8;
5825                                 break;
5826                         default:
5827                                 g_assert (mini_type_is_reference (fsig->params [1]));
5828                                 ins->type = STACK_OBJ;
5829                                 break;
5830                         }
5831
5832                         if (is_float) {
5833                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5834                                 i2f->dreg = mono_alloc_freg (cfg);
5835                                 i2f->sreg1 = ins->dreg;
5836                                 i2f->type = STACK_R8;
5837                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5838                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5839                                 MONO_ADD_INS (cfg->cbb, i2f);
5840
5841                                 ins = i2f;
5842                         }
5843
5844                         if (cfg->gen_write_barriers && is_ref)
5845                                 emit_write_barrier (cfg, args [0], args [1]);
5846                 }
5847                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
5848                          fsig->params [1]->type == MONO_TYPE_I4) {
5849                         MonoInst *cmp, *ceq;
5850
5851                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5852                                 return NULL;
5853
5854                         /* int32 r = CAS (location, value, comparand); */
5855                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5856                         ins->dreg = alloc_ireg (cfg);
5857                         ins->sreg1 = args [0]->dreg;
5858                         ins->sreg2 = args [1]->dreg;
5859                         ins->sreg3 = args [2]->dreg;
5860                         ins->type = STACK_I4;
5861                         MONO_ADD_INS (cfg->cbb, ins);
5862
5863                         /* bool result = r == comparand; */
5864                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
5865                         cmp->sreg1 = ins->dreg;
5866                         cmp->sreg2 = args [2]->dreg;
5867                         cmp->type = STACK_I4;
5868                         MONO_ADD_INS (cfg->cbb, cmp);
5869
5870                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
5871                         ceq->dreg = alloc_ireg (cfg);
5872                         ceq->type = STACK_I4;
5873                         MONO_ADD_INS (cfg->cbb, ceq);
5874
5875                         /* *success = result; */
5876                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
5877
5878                         cfg->has_atomic_cas_i4 = TRUE;
5879                 }
5880                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
5881                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5882
5883                 if (ins)
5884                         return ins;
5885         } else if (cmethod->klass->image == mono_defaults.corlib &&
5886                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5887                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
5888                 ins = NULL;
5889
5890                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
5891                         guint32 opcode = 0;
5892                         MonoType *t = fsig->params [0];
5893                         gboolean is_ref;
5894                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
5895
5896                         g_assert (t->byref);
5897                         /* t is a byref type, so the reference check is more complicated */
5898                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5899                         if (t->type == MONO_TYPE_I1)
5900                                 opcode = OP_ATOMIC_LOAD_I1;
5901                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5902                                 opcode = OP_ATOMIC_LOAD_U1;
5903                         else if (t->type == MONO_TYPE_I2)
5904                                 opcode = OP_ATOMIC_LOAD_I2;
5905                         else if (t->type == MONO_TYPE_U2)
5906                                 opcode = OP_ATOMIC_LOAD_U2;
5907                         else if (t->type == MONO_TYPE_I4)
5908                                 opcode = OP_ATOMIC_LOAD_I4;
5909                         else if (t->type == MONO_TYPE_U4)
5910                                 opcode = OP_ATOMIC_LOAD_U4;
5911                         else if (t->type == MONO_TYPE_R4)
5912                                 opcode = OP_ATOMIC_LOAD_R4;
5913                         else if (t->type == MONO_TYPE_R8)
5914                                 opcode = OP_ATOMIC_LOAD_R8;
5915 #if SIZEOF_REGISTER == 8
5916                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
5917                                 opcode = OP_ATOMIC_LOAD_I8;
5918                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
5919                                 opcode = OP_ATOMIC_LOAD_U8;
5920 #else
5921                         else if (t->type == MONO_TYPE_I)
5922                                 opcode = OP_ATOMIC_LOAD_I4;
5923                         else if (is_ref || t->type == MONO_TYPE_U)
5924                                 opcode = OP_ATOMIC_LOAD_U4;
5925 #endif
5926
5927                         if (opcode) {
5928                                 if (!mono_arch_opcode_supported (opcode))
5929                                         return NULL;
5930
5931                                 MONO_INST_NEW (cfg, ins, opcode);
5932                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
5933                                 ins->sreg1 = args [0]->dreg;
5934                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
5935                                 MONO_ADD_INS (cfg->cbb, ins);
5936
5937                                 switch (t->type) {
5938                                 case MONO_TYPE_BOOLEAN:
5939                                 case MONO_TYPE_I1:
5940                                 case MONO_TYPE_U1:
5941                                 case MONO_TYPE_I2:
5942                                 case MONO_TYPE_U2:
5943                                 case MONO_TYPE_I4:
5944                                 case MONO_TYPE_U4:
5945                                         ins->type = STACK_I4;
5946                                         break;
5947                                 case MONO_TYPE_I8:
5948                                 case MONO_TYPE_U8:
5949                                         ins->type = STACK_I8;
5950                                         break;
5951                                 case MONO_TYPE_I:
5952                                 case MONO_TYPE_U:
5953 #if SIZEOF_REGISTER == 8
5954                                         ins->type = STACK_I8;
5955 #else
5956                                         ins->type = STACK_I4;
5957 #endif
5958                                         break;
5959                                 case MONO_TYPE_R4:
5960                                         ins->type = cfg->r4_stack_type;
5961                                         break;
5962                                 case MONO_TYPE_R8:
5963                                         ins->type = STACK_R8;
5964                                         break;
5965                                 default:
5966                                         g_assert (is_ref);
5967                                         ins->type = STACK_OBJ;
5968                                         break;
5969                                 }
5970                         }
5971                 }
5972
5973                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
5974                         guint32 opcode = 0;
5975                         MonoType *t = fsig->params [0];
5976                         gboolean is_ref;
5977
5978                         g_assert (t->byref);
5979                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5980                         if (t->type == MONO_TYPE_I1)
5981                                 opcode = OP_ATOMIC_STORE_I1;
5982                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5983                                 opcode = OP_ATOMIC_STORE_U1;
5984                         else if (t->type == MONO_TYPE_I2)
5985                                 opcode = OP_ATOMIC_STORE_I2;
5986                         else if (t->type == MONO_TYPE_U2)
5987                                 opcode = OP_ATOMIC_STORE_U2;
5988                         else if (t->type == MONO_TYPE_I4)
5989                                 opcode = OP_ATOMIC_STORE_I4;
5990                         else if (t->type == MONO_TYPE_U4)
5991                                 opcode = OP_ATOMIC_STORE_U4;
5992                         else if (t->type == MONO_TYPE_R4)
5993                                 opcode = OP_ATOMIC_STORE_R4;
5994                         else if (t->type == MONO_TYPE_R8)
5995                                 opcode = OP_ATOMIC_STORE_R8;
5996 #if SIZEOF_REGISTER == 8
5997                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
5998                                 opcode = OP_ATOMIC_STORE_I8;
5999                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6000                                 opcode = OP_ATOMIC_STORE_U8;
6001 #else
6002                         else if (t->type == MONO_TYPE_I)
6003                                 opcode = OP_ATOMIC_STORE_I4;
6004                         else if (is_ref || t->type == MONO_TYPE_U)
6005                                 opcode = OP_ATOMIC_STORE_U4;
6006 #endif
6007
6008                         if (opcode) {
6009                                 if (!mono_arch_opcode_supported (opcode))
6010                                         return NULL;
6011
6012                                 MONO_INST_NEW (cfg, ins, opcode);
6013                                 ins->dreg = args [0]->dreg;
6014                                 ins->sreg1 = args [1]->dreg;
6015                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6016                                 MONO_ADD_INS (cfg->cbb, ins);
6017
6018                                 if (cfg->gen_write_barriers && is_ref)
6019                                         emit_write_barrier (cfg, args [0], args [1]);
6020                         }
6021                 }
6022
6023                 if (ins)
6024                         return ins;
6025         } else if (cmethod->klass->image == mono_defaults.corlib &&
6026                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6027                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6028                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6029                         if (should_insert_brekpoint (cfg->method)) {
6030                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6031                         } else {
6032                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6033                                 MONO_ADD_INS (cfg->cbb, ins);
6034                         }
6035                         return ins;
6036                 }
6037         } else if (cmethod->klass->image == mono_defaults.corlib &&
6038                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6039                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6040                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6041 #ifdef TARGET_WIN32
6042                         EMIT_NEW_ICONST (cfg, ins, 1);
6043 #else
6044                         EMIT_NEW_ICONST (cfg, ins, 0);
6045 #endif
6046                 }
6047         } else if (cmethod->klass->image == mono_defaults.corlib &&
6048                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6049                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6050                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6051                         /* No stack walks are currently available, so implement this as an intrinsic */
6052                         MonoInst *assembly_ins;
6053
6054                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6055                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6056                         return ins;
6057                 }
6058         } else if (cmethod->klass->image == mono_defaults.corlib &&
6059                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6060                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6061                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6062                         /* No stack walks are currently available, so implement this as an intrinsic */
6063                         MonoInst *method_ins;
6064                         MonoMethod *declaring = cfg->method;
6065
6066                         /* This returns the declaring generic method */
6067                         if (declaring->is_inflated)
6068                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6069                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6070                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6071                         cfg->no_inline = TRUE;
6072                         if (cfg->method != cfg->current_method)
6073                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6074                         return ins;
6075                 }
6076         } else if (cmethod->klass == mono_defaults.math_class) {
6077                 /* 
6078                  * There is general branchless code for Min/Max, but it does not work for 
6079                  * all inputs:
6080                  * http://everything2.com/?node_id=1051618
6081                  */
6082         } else if (cmethod->klass == mono_defaults.systemtype_class && !strcmp (cmethod->name, "op_Equality")) {
6083                 EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg);
6084                 MONO_INST_NEW (cfg, ins, OP_PCEQ);
6085                 ins->dreg = alloc_preg (cfg);
6086                 ins->type = STACK_I4;
6087                 MONO_ADD_INS (cfg->cbb, ins);
6088                 return ins;
6089         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6090                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6091                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6092                                 !strcmp (cmethod->klass->name, "Selector")) ||
6093                            ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
6094                                  !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
6095                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6096                                 !strcmp (cmethod->klass->name, "Selector"))
6097                            ) {
6098                 if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
6099                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6100                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6101                     cfg->compile_aot) {
6102                         MonoInst *pi;
6103                         MonoJumpInfoToken *ji;
6104                         char *s;
6105
6106                         if (args [0]->opcode == OP_GOT_ENTRY) {
6107                                 pi = (MonoInst *)args [0]->inst_p1;
6108                                 g_assert (pi->opcode == OP_PATCH_INFO);
6109                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6110                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6111                         } else {
6112                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6113                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6114                         }
6115
6116                         NULLIFY_INS (args [0]);
6117
6118                         s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
6119                         return_val_if_nok (&cfg->error, NULL);
6120
6121                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6122                         ins->dreg = mono_alloc_ireg (cfg);
6123                         // FIXME: Leaks
6124                         ins->inst_p0 = s;
6125                         MONO_ADD_INS (cfg->cbb, ins);
6126                         return ins;
6127                 }
6128         }
6129
6130 #ifdef MONO_ARCH_SIMD_INTRINSICS
6131         if (cfg->opt & MONO_OPT_SIMD) {
6132                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6133                 if (ins)
6134                         return ins;
6135         }
6136 #endif
6137
6138         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6139         if (ins)
6140                 return ins;
6141
6142         if (COMPILE_LLVM (cfg)) {
6143                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6144                 if (ins)
6145                         return ins;
6146         }
6147
6148         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6149 }
6150
6151 /*
6152  * This entry point could be used later for arbitrary method
6153  * redirection.
6154  */
6155 inline static MonoInst*
6156 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6157                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6158 {
6159         if (method->klass == mono_defaults.string_class) {
6160                 /* managed string allocation support */
6161                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6162                         MonoInst *iargs [2];
6163                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6164                         MonoMethod *managed_alloc = NULL;
6165
6166                         g_assert (vtable); /*Should not fail since it System.String*/
6167 #ifndef MONO_CROSS_COMPILE
6168                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6169 #endif
6170                         if (!managed_alloc)
6171                                 return NULL;
6172                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6173                         iargs [1] = args [0];
6174                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6175                 }
6176         }
6177         return NULL;
6178 }
6179
6180 static void
6181 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6182 {
6183         MonoInst *store, *temp;
6184         int i;
6185
6186         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6187                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6188
6189                 /*
6190                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6191                  * would be different than the MonoInst's used to represent arguments, and
6192                  * the ldelema implementation can't deal with that.
6193                  * Solution: When ldelema is used on an inline argument, create a var for 
6194                  * it, emit ldelema on that var, and emit the saving code below in
6195                  * inline_method () if needed.
6196                  */
6197                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6198                 cfg->args [i] = temp;
6199                 /* This uses cfg->args [i] which is set by the preceeding line */
6200                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6201                 store->cil_code = sp [0]->cil_code;
6202                 sp++;
6203         }
6204 }
6205
6206 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6207 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6208
6209 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6210 static gboolean
6211 check_inline_called_method_name_limit (MonoMethod *called_method)
6212 {
6213         int strncmp_result;
6214         static const char *limit = NULL;
6215         
6216         if (limit == NULL) {
6217                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6218
6219                 if (limit_string != NULL)
6220                         limit = limit_string;
6221                 else
6222                         limit = "";
6223         }
6224
6225         if (limit [0] != '\0') {
6226                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6227
6228                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6229                 g_free (called_method_name);
6230         
6231                 //return (strncmp_result <= 0);
6232                 return (strncmp_result == 0);
6233         } else {
6234                 return TRUE;
6235         }
6236 }
6237 #endif
6238
6239 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6240 static gboolean
6241 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6242 {
6243         int strncmp_result;
6244         static const char *limit = NULL;
6245         
6246         if (limit == NULL) {
6247                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6248                 if (limit_string != NULL) {
6249                         limit = limit_string;
6250                 } else {
6251                         limit = "";
6252                 }
6253         }
6254
6255         if (limit [0] != '\0') {
6256                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6257
6258                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6259                 g_free (caller_method_name);
6260         
6261                 //return (strncmp_result <= 0);
6262                 return (strncmp_result == 0);
6263         } else {
6264                 return TRUE;
6265         }
6266 }
6267 #endif
6268
6269 static void
6270 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6271 {
6272         static double r8_0 = 0.0;
6273         static float r4_0 = 0.0;
6274         MonoInst *ins;
6275         int t;
6276
6277         rtype = mini_get_underlying_type (rtype);
6278         t = rtype->type;
6279
6280         if (rtype->byref) {
6281                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6282         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6283                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6284         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6285                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6286         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6287                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6288                 ins->type = STACK_R4;
6289                 ins->inst_p0 = (void*)&r4_0;
6290                 ins->dreg = dreg;
6291                 MONO_ADD_INS (cfg->cbb, ins);
6292         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6293                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6294                 ins->type = STACK_R8;
6295                 ins->inst_p0 = (void*)&r8_0;
6296                 ins->dreg = dreg;
6297                 MONO_ADD_INS (cfg->cbb, ins);
6298         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6299                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6300                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6301         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6302                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6303         } else {
6304                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6305         }
6306 }
6307
6308 static void
6309 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6310 {
6311         int t;
6312
6313         rtype = mini_get_underlying_type (rtype);
6314         t = rtype->type;
6315
6316         if (rtype->byref) {
6317                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6318         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6319                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6320         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6321                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6322         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6323                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6324         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6325                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6326         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6327                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6328                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6329         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6330                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6331         } else {
6332                 emit_init_rvar (cfg, dreg, rtype);
6333         }
6334 }
6335
6336 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6337 static void
6338 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6339 {
6340         MonoInst *var = cfg->locals [local];
6341         if (COMPILE_SOFT_FLOAT (cfg)) {
6342                 MonoInst *store;
6343                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
6344                 emit_init_rvar (cfg, reg, type);
6345                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6346         } else {
6347                 if (init)
6348                         emit_init_rvar (cfg, var->dreg, type);
6349                 else
6350                         emit_dummy_init_rvar (cfg, var->dreg, type);
6351         }
6352 }
6353
6354 int
6355 mini_inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, guchar *ip, guint real_offset, gboolean inline_always)
6356 {
6357         return inline_method (cfg, cmethod, fsig, sp, ip, real_offset, inline_always);
6358 }
6359
6360 /*
6361  * inline_method:
6362  *
6363  * Return the cost of inlining CMETHOD, or zero if it should not be inlined.
6364  */
6365 static int
6366 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6367                guchar *ip, guint real_offset, gboolean inline_always)
6368 {
6369         MonoError error;
6370         MonoInst *ins, *rvar = NULL;
6371         MonoMethodHeader *cheader;
6372         MonoBasicBlock *ebblock, *sbblock;
6373         int i, costs;
6374         MonoMethod *prev_inlined_method;
6375         MonoInst **prev_locals, **prev_args;
6376         MonoType **prev_arg_types;
6377         guint prev_real_offset;
6378         GHashTable *prev_cbb_hash;
6379         MonoBasicBlock **prev_cil_offset_to_bb;
6380         MonoBasicBlock *prev_cbb;
6381         const unsigned char *prev_ip;
6382         unsigned char *prev_cil_start;
6383         guint32 prev_cil_offset_to_bb_len;
6384         MonoMethod *prev_current_method;
6385         MonoGenericContext *prev_generic_context;
6386         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
6387
6388         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6389
6390 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6391         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6392                 return 0;
6393 #endif
6394 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6395         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6396                 return 0;
6397 #endif
6398
6399         if (!fsig)
6400                 fsig = mono_method_signature (cmethod);
6401
6402         if (cfg->verbose_level > 2)
6403                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6404
6405         if (!cmethod->inline_info) {
6406                 cfg->stat_inlineable_methods++;
6407                 cmethod->inline_info = 1;
6408         }
6409
6410         /* allocate local variables */
6411         cheader = mono_method_get_header_checked (cmethod, &error);
6412         if (!cheader) {
6413                 if (inline_always) {
6414                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
6415                         mono_error_move (&cfg->error, &error);
6416                 } else {
6417                         mono_error_cleanup (&error);
6418                 }
6419                 return 0;
6420         }
6421
6422         /*Must verify before creating locals as it can cause the JIT to assert.*/
6423         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6424                 mono_metadata_free_mh (cheader);
6425                 return 0;
6426         }
6427
6428         /* allocate space to store the return value */
6429         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6430                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6431         }
6432
6433         prev_locals = cfg->locals;
6434         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
6435         for (i = 0; i < cheader->num_locals; ++i)
6436                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6437
6438         /* allocate start and end blocks */
6439         /* This is needed so if the inline is aborted, we can clean up */
6440         NEW_BBLOCK (cfg, sbblock);
6441         sbblock->real_offset = real_offset;
6442
6443         NEW_BBLOCK (cfg, ebblock);
6444         ebblock->block_num = cfg->num_bblocks++;
6445         ebblock->real_offset = real_offset;
6446
6447         prev_args = cfg->args;
6448         prev_arg_types = cfg->arg_types;
6449         prev_inlined_method = cfg->inlined_method;
6450         cfg->inlined_method = cmethod;
6451         cfg->ret_var_set = FALSE;
6452         cfg->inline_depth ++;
6453         prev_real_offset = cfg->real_offset;
6454         prev_cbb_hash = cfg->cbb_hash;
6455         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6456         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6457         prev_cil_start = cfg->cil_start;
6458         prev_ip = cfg->ip;
6459         prev_cbb = cfg->cbb;
6460         prev_current_method = cfg->current_method;
6461         prev_generic_context = cfg->generic_context;
6462         prev_ret_var_set = cfg->ret_var_set;
6463         prev_disable_inline = cfg->disable_inline;
6464
6465         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6466                 virtual_ = TRUE;
6467
6468         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
6469
6470         ret_var_set = cfg->ret_var_set;
6471
6472         cfg->inlined_method = prev_inlined_method;
6473         cfg->real_offset = prev_real_offset;
6474         cfg->cbb_hash = prev_cbb_hash;
6475         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6476         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6477         cfg->cil_start = prev_cil_start;
6478         cfg->ip = prev_ip;
6479         cfg->locals = prev_locals;
6480         cfg->args = prev_args;
6481         cfg->arg_types = prev_arg_types;
6482         cfg->current_method = prev_current_method;
6483         cfg->generic_context = prev_generic_context;
6484         cfg->ret_var_set = prev_ret_var_set;
6485         cfg->disable_inline = prev_disable_inline;
6486         cfg->inline_depth --;
6487
6488         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
6489                 if (cfg->verbose_level > 2)
6490                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6491
6492                 cfg->stat_inlined_methods++;
6493
6494                 /* always add some code to avoid block split failures */
6495                 MONO_INST_NEW (cfg, ins, OP_NOP);
6496                 MONO_ADD_INS (prev_cbb, ins);
6497
6498                 prev_cbb->next_bb = sbblock;
6499                 link_bblock (cfg, prev_cbb, sbblock);
6500
6501                 /* 
6502                  * Get rid of the begin and end bblocks if possible to aid local
6503                  * optimizations.
6504                  */
6505                 if (prev_cbb->out_count == 1)
6506                         mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6507
6508                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6509                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6510
6511                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6512                         MonoBasicBlock *prev = ebblock->in_bb [0];
6513
6514                         if (prev->next_bb == ebblock) {
6515                                 mono_merge_basic_blocks (cfg, prev, ebblock);
6516                                 cfg->cbb = prev;
6517                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6518                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
6519                                         cfg->cbb = prev_cbb;
6520                                 }
6521                         } else {
6522                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
6523                                 cfg->cbb = ebblock;
6524                         }
6525                 } else {
6526                         /* 
6527                          * Its possible that the rvar is set in some prev bblock, but not in others.
6528                          * (#1835).
6529                          */
6530                         if (rvar) {
6531                                 MonoBasicBlock *bb;
6532
6533                                 for (i = 0; i < ebblock->in_count; ++i) {
6534                                         bb = ebblock->in_bb [i];
6535
6536                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6537                                                 cfg->cbb = bb;
6538
6539                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6540                                         }
6541                                 }
6542                         }
6543
6544                         cfg->cbb = ebblock;
6545                 }
6546
6547                 if (rvar) {
6548                         /*
6549                          * If the inlined method contains only a throw, then the ret var is not 
6550                          * set, so set it to a dummy value.
6551                          */
6552                         if (!ret_var_set)
6553                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6554
6555                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6556                         *sp++ = ins;
6557                 }
6558                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6559                 return costs + 1;
6560         } else {
6561                 if (cfg->verbose_level > 2)
6562                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6563                 cfg->exception_type = MONO_EXCEPTION_NONE;
6564
6565                 /* This gets rid of the newly added bblocks */
6566                 cfg->cbb = prev_cbb;
6567         }
6568         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6569         return 0;
6570 }
6571
6572 /*
6573  * Some of these comments may well be out-of-date.
6574  * Design decisions: we do a single pass over the IL code (and we do bblock 
6575  * splitting/merging in the few cases when it's required: a back jump to an IL
6576  * address that was not already seen as bblock starting point).
6577  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6578  * Complex operations are decomposed in simpler ones right away. We need to let the 
6579  * arch-specific code peek and poke inside this process somehow (except when the 
6580  * optimizations can take advantage of the full semantic info of coarse opcodes).
6581  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6582  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6583  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6584  * opcode with value bigger than OP_LAST.
6585  * At this point the IR can be handed over to an interpreter, a dumb code generator
6586  * or to the optimizing code generator that will translate it to SSA form.
6587  *
6588  * Profiling directed optimizations.
6589  * We may compile by default with few or no optimizations and instrument the code
6590  * or the user may indicate what methods to optimize the most either in a config file
6591  * or through repeated runs where the compiler applies offline the optimizations to 
6592  * each method and then decides if it was worth it.
6593  */
6594
6595 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6596 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6597 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6598 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6599 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6600 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6601 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6602 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
6603
6604 /* offset from br.s -> br like opcodes */
6605 #define BIG_BRANCH_OFFSET 13
6606
6607 static gboolean
6608 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6609 {
6610         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6611
6612         return b == NULL || b == bb;
6613 }
6614
6615 static int
6616 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6617 {
6618         unsigned char *ip = start;
6619         unsigned char *target;
6620         int i;
6621         guint cli_addr;
6622         MonoBasicBlock *bblock;
6623         const MonoOpcode *opcode;
6624
6625         while (ip < end) {
6626                 cli_addr = ip - start;
6627                 i = mono_opcode_value ((const guint8 **)&ip, end);
6628                 if (i < 0)
6629                         UNVERIFIED;
6630                 opcode = &mono_opcodes [i];
6631                 switch (opcode->argument) {
6632                 case MonoInlineNone:
6633                         ip++; 
6634                         break;
6635                 case MonoInlineString:
6636                 case MonoInlineType:
6637                 case MonoInlineField:
6638                 case MonoInlineMethod:
6639                 case MonoInlineTok:
6640                 case MonoInlineSig:
6641                 case MonoShortInlineR:
6642                 case MonoInlineI:
6643                         ip += 5;
6644                         break;
6645                 case MonoInlineVar:
6646                         ip += 3;
6647                         break;
6648                 case MonoShortInlineVar:
6649                 case MonoShortInlineI:
6650                         ip += 2;
6651                         break;
6652                 case MonoShortInlineBrTarget:
6653                         target = start + cli_addr + 2 + (signed char)ip [1];
6654                         GET_BBLOCK (cfg, bblock, target);
6655                         ip += 2;
6656                         if (ip < end)
6657                                 GET_BBLOCK (cfg, bblock, ip);
6658                         break;
6659                 case MonoInlineBrTarget:
6660                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6661                         GET_BBLOCK (cfg, bblock, target);
6662                         ip += 5;
6663                         if (ip < end)
6664                                 GET_BBLOCK (cfg, bblock, ip);
6665                         break;
6666                 case MonoInlineSwitch: {
6667                         guint32 n = read32 (ip + 1);
6668                         guint32 j;
6669                         ip += 5;
6670                         cli_addr += 5 + 4 * n;
6671                         target = start + cli_addr;
6672                         GET_BBLOCK (cfg, bblock, target);
6673                         
6674                         for (j = 0; j < n; ++j) {
6675                                 target = start + cli_addr + (gint32)read32 (ip);
6676                                 GET_BBLOCK (cfg, bblock, target);
6677                                 ip += 4;
6678                         }
6679                         break;
6680                 }
6681                 case MonoInlineR:
6682                 case MonoInlineI8:
6683                         ip += 9;
6684                         break;
6685                 default:
6686                         g_assert_not_reached ();
6687                 }
6688
6689                 if (i == CEE_THROW) {
6690                         unsigned char *bb_start = ip - 1;
6691                         
6692                         /* Find the start of the bblock containing the throw */
6693                         bblock = NULL;
6694                         while ((bb_start >= start) && !bblock) {
6695                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6696                                 bb_start --;
6697                         }
6698                         if (bblock)
6699                                 bblock->out_of_line = 1;
6700                 }
6701         }
6702         return 0;
6703 unverified:
6704 exception_exit:
6705         *pos = ip;
6706         return 1;
6707 }
6708
6709 static inline MonoMethod *
6710 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
6711 {
6712         MonoMethod *method;
6713
6714         error_init (error);
6715
6716         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6717                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
6718                 if (context) {
6719                         method = mono_class_inflate_generic_method_checked (method, context, error);
6720                 }
6721         } else {
6722                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
6723         }
6724
6725         return method;
6726 }
6727
6728 static inline MonoMethod *
6729 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6730 {
6731         MonoError error;
6732         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
6733
6734         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
6735                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
6736                 method = NULL;
6737         }
6738
6739         if (!method && !cfg)
6740                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6741
6742         return method;
6743 }
6744
6745 static inline MonoClass*
6746 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6747 {
6748         MonoError error;
6749         MonoClass *klass;
6750
6751         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6752                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
6753                 if (context) {
6754                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
6755                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6756                 }
6757         } else {
6758                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
6759                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6760         }
6761         if (klass)
6762                 mono_class_init (klass);
6763         return klass;
6764 }
6765
6766 static inline MonoMethodSignature*
6767 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
6768 {
6769         MonoMethodSignature *fsig;
6770
6771         error_init (error);
6772         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6773                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6774         } else {
6775                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
6776                 return_val_if_nok (error, NULL);
6777         }
6778         if (context) {
6779                 fsig = mono_inflate_generic_signature(fsig, context, error);
6780         }
6781         return fsig;
6782 }
6783
6784 static MonoMethod*
6785 throw_exception (void)
6786 {
6787         static MonoMethod *method = NULL;
6788
6789         if (!method) {
6790                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6791                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6792         }
6793         g_assert (method);
6794         return method;
6795 }
6796
6797 static void
6798 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6799 {
6800         MonoMethod *thrower = throw_exception ();
6801         MonoInst *args [1];
6802
6803         EMIT_NEW_PCONST (cfg, args [0], ex);
6804         mono_emit_method_call (cfg, thrower, args, NULL);
6805 }
6806
6807 /*
6808  * Return the original method is a wrapper is specified. We can only access 
6809  * the custom attributes from the original method.
6810  */
6811 static MonoMethod*
6812 get_original_method (MonoMethod *method)
6813 {
6814         if (method->wrapper_type == MONO_WRAPPER_NONE)
6815                 return method;
6816
6817         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6818         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6819                 return NULL;
6820
6821         /* in other cases we need to find the original method */
6822         return mono_marshal_method_from_wrapper (method);
6823 }
6824
6825 static void
6826 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
6827 {
6828         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6829         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6830         if (ex)
6831                 emit_throw_exception (cfg, ex);
6832 }
6833
6834 static void
6835 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6836 {
6837         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6838         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6839         if (ex)
6840                 emit_throw_exception (cfg, ex);
6841 }
6842
6843 /*
6844  * Check that the IL instructions at ip are the array initialization
6845  * sequence and return the pointer to the data and the size.
6846  */
6847 static const char*
6848 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6849 {
6850         /*
6851          * newarr[System.Int32]
6852          * dup
6853          * ldtoken field valuetype ...
6854          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6855          */
6856         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6857                 MonoError error;
6858                 guint32 token = read32 (ip + 7);
6859                 guint32 field_token = read32 (ip + 2);
6860                 guint32 field_index = field_token & 0xffffff;
6861                 guint32 rva;
6862                 const char *data_ptr;
6863                 int size = 0;
6864                 MonoMethod *cmethod;
6865                 MonoClass *dummy_class;
6866                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
6867                 int dummy_align;
6868
6869                 if (!field) {
6870                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6871                         return NULL;
6872                 }
6873
6874                 *out_field_token = field_token;
6875
6876                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6877                 if (!cmethod)
6878                         return NULL;
6879                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6880                         return NULL;
6881                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6882                 case MONO_TYPE_BOOLEAN:
6883                 case MONO_TYPE_I1:
6884                 case MONO_TYPE_U1:
6885                         size = 1; break;
6886                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6887 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6888                 case MONO_TYPE_CHAR:
6889                 case MONO_TYPE_I2:
6890                 case MONO_TYPE_U2:
6891                         size = 2; break;
6892                 case MONO_TYPE_I4:
6893                 case MONO_TYPE_U4:
6894                 case MONO_TYPE_R4:
6895                         size = 4; break;
6896                 case MONO_TYPE_R8:
6897                 case MONO_TYPE_I8:
6898                 case MONO_TYPE_U8:
6899                         size = 8; break;
6900 #endif
6901                 default:
6902                         return NULL;
6903                 }
6904                 size *= len;
6905                 if (size > mono_type_size (field->type, &dummy_align))
6906                     return NULL;
6907                 *out_size = size;
6908                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6909                 if (!image_is_dynamic (method->klass->image)) {
6910                         field_index = read32 (ip + 2) & 0xffffff;
6911                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6912                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6913                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6914                         /* for aot code we do the lookup on load */
6915                         if (aot && data_ptr)
6916                                 return (const char *)GUINT_TO_POINTER (rva);
6917                 } else {
6918                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6919                         g_assert (!aot);
6920                         data_ptr = mono_field_get_data (field);
6921                 }
6922                 return data_ptr;
6923         }
6924         return NULL;
6925 }
6926
6927 static void
6928 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6929 {
6930         MonoError error;
6931         char *method_fname = mono_method_full_name (method, TRUE);
6932         char *method_code;
6933         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
6934
6935         if (!header) {
6936                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
6937                 mono_error_cleanup (&error);
6938         } else if (header->code_size == 0)
6939                 method_code = g_strdup ("method body is empty.");
6940         else
6941                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6942         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
6943         g_free (method_fname);
6944         g_free (method_code);
6945         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6946 }
6947
6948 static void
6949 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6950 {
6951         MonoInst *ins;
6952         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6953         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6954                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6955                 /* Optimize reg-reg moves away */
6956                 /* 
6957                  * Can't optimize other opcodes, since sp[0] might point to
6958                  * the last ins of a decomposed opcode.
6959                  */
6960                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6961         } else {
6962                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6963         }
6964 }
6965
6966 /*
6967  * ldloca inhibits many optimizations so try to get rid of it in common
6968  * cases.
6969  */
6970 static inline unsigned char *
6971 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6972 {
6973         int local, token;
6974         MonoClass *klass;
6975         MonoType *type;
6976
6977         if (size == 1) {
6978                 local = ip [1];
6979                 ip += 2;
6980         } else {
6981                 local = read16 (ip + 2);
6982                 ip += 4;
6983         }
6984         
6985         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6986                 /* From the INITOBJ case */
6987                 token = read32 (ip + 2);
6988                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6989                 CHECK_TYPELOAD (klass);
6990                 type = mini_get_underlying_type (&klass->byval_arg);
6991                 emit_init_local (cfg, local, type, TRUE);
6992                 return ip + 6;
6993         }
6994  exception_exit:
6995         return NULL;
6996 }
6997
6998 static MonoInst*
6999 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7000 {
7001         MonoInst *icall_args [16];
7002         MonoInst *call_target, *ins, *vtable_ins;
7003         int arg_reg, this_reg, vtable_reg;
7004         gboolean is_iface = mono_class_is_interface (cmethod->klass);
7005         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7006         gboolean variant_iface = FALSE;
7007         guint32 slot;
7008         int offset;
7009         gboolean special_array_interface = cmethod->klass->is_array_special_interface;
7010
7011         /*
7012          * In llvm-only mode, vtables contain function descriptors instead of
7013          * method addresses/trampolines.
7014          */
7015         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7016
7017         if (is_iface)
7018                 slot = mono_method_get_imt_slot (cmethod);
7019         else
7020                 slot = mono_method_get_vtable_index (cmethod);
7021
7022         this_reg = sp [0]->dreg;
7023
7024         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7025                 variant_iface = TRUE;
7026
7027         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7028                 /*
7029                  * The simplest case, a normal virtual call.
7030                  */
7031                 int slot_reg = alloc_preg (cfg);
7032                 int addr_reg = alloc_preg (cfg);
7033                 int arg_reg = alloc_preg (cfg);
7034                 MonoBasicBlock *non_null_bb;
7035
7036                 vtable_reg = alloc_preg (cfg);
7037                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7038                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7039
7040                 /* Load the vtable slot, which contains a function descriptor. */
7041                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7042
7043                 NEW_BBLOCK (cfg, non_null_bb);
7044
7045                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7046                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7047                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7048
7049                 /* Slow path */
7050                 // FIXME: Make the wrapper use the preserveall cconv
7051                 // FIXME: Use one icall per slot for small slot numbers ?
7052                 icall_args [0] = vtable_ins;
7053                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7054                 /* Make the icall return the vtable slot value to save some code space */
7055                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7056                 ins->dreg = slot_reg;
7057                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7058
7059                 /* Fastpath */
7060                 MONO_START_BB (cfg, non_null_bb);
7061                 /* Load the address + arg from the vtable slot */
7062                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7063                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7064
7065                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7066         }
7067
7068         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt && !special_array_interface) {
7069                 /*
7070                  * A simple interface call
7071                  *
7072                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7073                  * The imt slot contains a function descriptor for a runtime function + arg.
7074                  */
7075                 int slot_reg = alloc_preg (cfg);
7076                 int addr_reg = alloc_preg (cfg);
7077                 int arg_reg = alloc_preg (cfg);
7078                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7079
7080                 vtable_reg = alloc_preg (cfg);
7081                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7082                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7083
7084                 /*
7085                  * The slot is already initialized when the vtable is created so there is no need
7086                  * to check it here.
7087                  */
7088
7089                 /* Load the imt slot, which contains a function descriptor. */
7090                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7091
7092                 /* Load the address + arg of the imt thunk from the imt slot */
7093                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7094                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7095                 /*
7096                  * IMT thunks in llvm-only mode are C functions which take an info argument
7097                  * plus the imt method and return the ftndesc to call.
7098                  */
7099                 icall_args [0] = thunk_arg_ins;
7100                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7101                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7102                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7103
7104                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7105         }
7106
7107         if ((fsig->generic_param_count || variant_iface || special_array_interface) && !is_gsharedvt) {
7108                 /*
7109                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7110                  * dynamically extended as more instantiations are discovered.
7111                  * This handles generic virtual methods both on classes and interfaces.
7112                  */
7113                 int slot_reg = alloc_preg (cfg);
7114                 int addr_reg = alloc_preg (cfg);
7115                 int arg_reg = alloc_preg (cfg);
7116                 int ftndesc_reg = alloc_preg (cfg);
7117                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7118                 MonoBasicBlock *slowpath_bb, *end_bb;
7119
7120                 NEW_BBLOCK (cfg, slowpath_bb);
7121                 NEW_BBLOCK (cfg, end_bb);
7122
7123                 vtable_reg = alloc_preg (cfg);
7124                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7125                 if (is_iface)
7126                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7127                 else
7128                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7129
7130                 /* Load the slot, which contains a function descriptor. */
7131                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7132
7133                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7134                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7135                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7136                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7137
7138                 /* Fastpath */
7139                 /* Same as with iface calls */
7140                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7141                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7142                 icall_args [0] = thunk_arg_ins;
7143                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7144                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7145                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7146                 ftndesc_ins->dreg = ftndesc_reg;
7147                 /*
7148                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7149                  * they don't know about yet. Fall back to the slowpath in that case.
7150                  */
7151                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7152                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7153
7154                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7155
7156                 /* Slowpath */
7157                 MONO_START_BB (cfg, slowpath_bb);
7158                 icall_args [0] = vtable_ins;
7159                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7160                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7161                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7162                 if (is_iface)
7163                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7164                 else
7165                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7166                 ftndesc_ins->dreg = ftndesc_reg;
7167                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7168
7169                 /* Common case */
7170                 MONO_START_BB (cfg, end_bb);
7171                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7172         }
7173
7174         /*
7175          * Non-optimized cases
7176          */
7177         icall_args [0] = sp [0];
7178         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7179
7180         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7181                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7182
7183         arg_reg = alloc_preg (cfg);
7184         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7185         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7186
7187         g_assert (is_gsharedvt);
7188         if (is_iface)
7189                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7190         else
7191                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7192
7193         /*
7194          * Pass the extra argument even if the callee doesn't receive it, most
7195          * calling conventions allow this.
7196          */
7197         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7198 }
7199
7200 static gboolean
7201 is_exception_class (MonoClass *klass)
7202 {
7203         while (klass) {
7204                 if (klass == mono_defaults.exception_class)
7205                         return TRUE;
7206                 klass = klass->parent;
7207         }
7208         return FALSE;
7209 }
7210
7211 /*
7212  * is_jit_optimizer_disabled:
7213  *
7214  *   Determine whenever M's assembly has a DebuggableAttribute with the
7215  * IsJITOptimizerDisabled flag set.
7216  */
7217 static gboolean
7218 is_jit_optimizer_disabled (MonoMethod *m)
7219 {
7220         MonoError error;
7221         MonoAssembly *ass = m->klass->image->assembly;
7222         MonoCustomAttrInfo* attrs;
7223         MonoClass *klass;
7224         int i;
7225         gboolean val = FALSE;
7226
7227         g_assert (ass);
7228         if (ass->jit_optimizer_disabled_inited)
7229                 return ass->jit_optimizer_disabled;
7230
7231         klass = mono_class_try_get_debuggable_attribute_class ();
7232
7233         if (!klass) {
7234                 /* Linked away */
7235                 ass->jit_optimizer_disabled = FALSE;
7236                 mono_memory_barrier ();
7237                 ass->jit_optimizer_disabled_inited = TRUE;
7238                 return FALSE;
7239         }
7240
7241         attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
7242         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7243         if (attrs) {
7244                 for (i = 0; i < attrs->num_attrs; ++i) {
7245                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7246                         const gchar *p;
7247                         MonoMethodSignature *sig;
7248
7249                         if (!attr->ctor || attr->ctor->klass != klass)
7250                                 continue;
7251                         /* Decode the attribute. See reflection.c */
7252                         p = (const char*)attr->data;
7253                         g_assert (read16 (p) == 0x0001);
7254                         p += 2;
7255
7256                         // FIXME: Support named parameters
7257                         sig = mono_method_signature (attr->ctor);
7258                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7259                                 continue;
7260                         /* Two boolean arguments */
7261                         p ++;
7262                         val = *p;
7263                 }
7264                 mono_custom_attrs_free (attrs);
7265         }
7266
7267         ass->jit_optimizer_disabled = val;
7268         mono_memory_barrier ();
7269         ass->jit_optimizer_disabled_inited = TRUE;
7270
7271         return val;
7272 }
7273
7274 static gboolean
7275 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7276 {
7277         gboolean supported_tail_call;
7278         int i;
7279
7280         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7281
7282         for (i = 0; i < fsig->param_count; ++i) {
7283                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7284                         /* These can point to the current method's stack */
7285                         supported_tail_call = FALSE;
7286         }
7287         if (fsig->hasthis && cmethod->klass->valuetype)
7288                 /* this might point to the current method's stack */
7289                 supported_tail_call = FALSE;
7290         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7291                 supported_tail_call = FALSE;
7292         if (cfg->method->save_lmf)
7293                 supported_tail_call = FALSE;
7294         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7295                 supported_tail_call = FALSE;
7296         if (call_opcode != CEE_CALL)
7297                 supported_tail_call = FALSE;
7298
7299         /* Debugging support */
7300 #if 0
7301         if (supported_tail_call) {
7302                 if (!mono_debug_count ())
7303                         supported_tail_call = FALSE;
7304         }
7305 #endif
7306
7307         return supported_tail_call;
7308 }
7309
7310 /*
7311  * handle_ctor_call:
7312  *
7313  *   Handle calls made to ctors from NEWOBJ opcodes.
7314  */
7315 static void
7316 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7317                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7318 {
7319         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7320
7321         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7322                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7323                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7324                         mono_class_vtable (cfg->domain, cmethod->klass);
7325                         CHECK_TYPELOAD (cmethod->klass);
7326
7327                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7328                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7329                 } else {
7330                         if (context_used) {
7331                                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
7332                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7333                         } else {
7334                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7335
7336                                 CHECK_TYPELOAD (cmethod->klass);
7337                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7338                         }
7339                 }
7340         }
7341
7342         /* Avoid virtual calls to ctors if possible */
7343         if (mono_class_is_marshalbyref (cmethod->klass))
7344                 callvirt_this_arg = sp [0];
7345
7346         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7347                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7348                 CHECK_CFG_EXCEPTION;
7349         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7350                            mono_method_check_inlining (cfg, cmethod) &&
7351                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7352                 int costs;
7353
7354                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7355                         cfg->real_offset += 5;
7356
7357                         *inline_costs += costs - 5;
7358                 } else {
7359                         INLINE_FAILURE ("inline failure");
7360                         // FIXME-VT: Clean this up
7361                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7362                                 GSHAREDVT_FAILURE(*ip);
7363                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7364                 }
7365         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7366                 MonoInst *addr;
7367
7368                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7369
7370                 if (cfg->llvm_only) {
7371                         // FIXME: Avoid initializing vtable_arg
7372                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7373                 } else {
7374                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7375                 }
7376         } else if (context_used &&
7377                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7378                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7379                 MonoInst *cmethod_addr;
7380
7381                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7382
7383                 if (cfg->llvm_only) {
7384                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
7385                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7386                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7387                 } else {
7388                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7389                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7390
7391                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7392                 }
7393         } else {
7394                 INLINE_FAILURE ("ctor call");
7395                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7396                                                                                   callvirt_this_arg, NULL, vtable_arg);
7397         }
7398  exception_exit:
7399         return;
7400 }
7401
7402 static void
7403 emit_setret (MonoCompile *cfg, MonoInst *val)
7404 {
7405         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7406         MonoInst *ins;
7407
7408         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7409                 MonoInst *ret_addr;
7410
7411                 if (!cfg->vret_addr) {
7412                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7413                 } else {
7414                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7415
7416                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7417                         ins->klass = mono_class_from_mono_type (ret_type);
7418                 }
7419         } else {
7420 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7421                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7422                         MonoInst *iargs [1];
7423                         MonoInst *conv;
7424
7425                         iargs [0] = val;
7426                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7427                         mono_arch_emit_setret (cfg, cfg->method, conv);
7428                 } else {
7429                         mono_arch_emit_setret (cfg, cfg->method, val);
7430                 }
7431 #else
7432                 mono_arch_emit_setret (cfg, cfg->method, val);
7433 #endif
7434         }
7435 }
7436
7437 /*
7438  * mono_method_to_ir:
7439  *
7440  * Translate the .net IL into linear IR.
7441  *
7442  * @start_bblock: if not NULL, the starting basic block, used during inlining.
7443  * @end_bblock: if not NULL, the ending basic block, used during inlining.
7444  * @return_var: if not NULL, the place where the return value is stored, used during inlining.   
7445  * @inline_args: if not NULL, contains the arguments to the inline call
7446  * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise.
7447  * @is_virtual_call: whether this method is being called as a result of a call to callvirt
7448  *
7449  * This method is used to turn ECMA IL into Mono's internal Linear IR
7450  * reprensetation.  It is used both for entire methods, as well as
7451  * inlining existing methods.  In the former case, the @start_bblock,
7452  * @end_bblock, @return_var, @inline_args are all set to NULL, and the
7453  * inline_offset is set to zero.
7454  * 
7455  * Returns: the inline cost, or -1 if there was an error processing this method.
7456  */
7457 int
7458 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7459                    MonoInst *return_var, MonoInst **inline_args, 
7460                    guint inline_offset, gboolean is_virtual_call)
7461 {
7462         MonoError error;
7463         MonoInst *ins, **sp, **stack_start;
7464         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7465         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7466         MonoMethod *cmethod, *method_definition;
7467         MonoInst **arg_array;
7468         MonoMethodHeader *header;
7469         MonoImage *image;
7470         guint32 token, ins_flag;
7471         MonoClass *klass;
7472         MonoClass *constrained_class = NULL;
7473         unsigned char *ip, *end, *target, *err_pos;
7474         MonoMethodSignature *sig;
7475         MonoGenericContext *generic_context = NULL;
7476         MonoGenericContainer *generic_container = NULL;
7477         MonoType **param_types;
7478         int i, n, start_new_bblock, dreg;
7479         int num_calls = 0, inline_costs = 0;
7480         int breakpoint_id = 0;
7481         guint num_args;
7482         GSList *class_inits = NULL;
7483         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7484         int context_used;
7485         gboolean init_locals, seq_points, skip_dead_blocks;
7486         gboolean sym_seq_points = FALSE;
7487         MonoDebugMethodInfo *minfo;
7488         MonoBitSet *seq_point_locs = NULL;
7489         MonoBitSet *seq_point_set_locs = NULL;
7490
7491         cfg->disable_inline = is_jit_optimizer_disabled (method);
7492
7493         /* serialization and xdomain stuff may need access to private fields and methods */
7494         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7495         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7496         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7497         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7498         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7499         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7500
7501         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7502         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7503         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7504         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7505         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7506
7507         image = method->klass->image;
7508         header = mono_method_get_header_checked (method, &cfg->error);
7509         if (!header) {
7510                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7511                 goto exception_exit;
7512         } else {
7513                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7514         }
7515
7516         generic_container = mono_method_get_generic_container (method);
7517         sig = mono_method_signature (method);
7518         num_args = sig->hasthis + sig->param_count;
7519         ip = (unsigned char*)header->code;
7520         cfg->cil_start = ip;
7521         end = ip + header->code_size;
7522         cfg->stat_cil_code_size += header->code_size;
7523
7524         seq_points = cfg->gen_seq_points && cfg->method == method;
7525
7526         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7527                 /* We could hit a seq point before attaching to the JIT (#8338) */
7528                 seq_points = FALSE;
7529         }
7530
7531         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7532                 minfo = mono_debug_lookup_method (method);
7533                 if (minfo) {
7534                         MonoSymSeqPoint *sps;
7535                         int i, n_il_offsets;
7536
7537                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7538                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7539                         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);
7540                         sym_seq_points = TRUE;
7541                         for (i = 0; i < n_il_offsets; ++i) {
7542                                 if (sps [i].il_offset < header->code_size)
7543                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7544                         }
7545                         g_free (sps);
7546
7547                         MonoDebugMethodAsyncInfo* asyncMethod = mono_debug_lookup_method_async_debug_info (method);
7548                         if (asyncMethod) {
7549                                 for (i = 0; asyncMethod != NULL && i < asyncMethod->num_awaits; i++)
7550                                 {
7551                                         mono_bitset_set_fast (seq_point_locs, asyncMethod->resume_offsets[i]);
7552                                         mono_bitset_set_fast (seq_point_locs, asyncMethod->yield_offsets[i]);
7553                                 }
7554                                 mono_debug_free_method_async_debug_info (asyncMethod);
7555                         }
7556                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7557                         /* Methods without line number info like auto-generated property accessors */
7558                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7559                         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);
7560                         sym_seq_points = TRUE;
7561                 }
7562         }
7563
7564         /* 
7565          * Methods without init_locals set could cause asserts in various passes
7566          * (#497220). To work around this, we emit dummy initialization opcodes
7567          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7568          * on some platforms.
7569          */
7570         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
7571                 init_locals = header->init_locals;
7572         else
7573                 init_locals = TRUE;
7574
7575         method_definition = method;
7576         while (method_definition->is_inflated) {
7577                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7578                 method_definition = imethod->declaring;
7579         }
7580
7581         /* SkipVerification is not allowed if core-clr is enabled */
7582         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7583                 dont_verify = TRUE;
7584                 dont_verify_stloc = TRUE;
7585         }
7586
7587         if (sig->is_inflated)
7588                 generic_context = mono_method_get_context (method);
7589         else if (generic_container)
7590                 generic_context = &generic_container->context;
7591         cfg->generic_context = generic_context;
7592
7593         if (!cfg->gshared)
7594                 g_assert (!sig->has_type_parameters);
7595
7596         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7597                 g_assert (method->is_inflated);
7598                 g_assert (mono_method_get_context (method)->method_inst);
7599         }
7600         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7601                 g_assert (sig->generic_param_count);
7602
7603         if (cfg->method == method) {
7604                 cfg->real_offset = 0;
7605         } else {
7606                 cfg->real_offset = inline_offset;
7607         }
7608
7609         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7610         cfg->cil_offset_to_bb_len = header->code_size;
7611
7612         cfg->current_method = method;
7613
7614         if (cfg->verbose_level > 2)
7615                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7616
7617         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7618         if (sig->hasthis)
7619                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7620         for (n = 0; n < sig->param_count; ++n)
7621                 param_types [n + sig->hasthis] = sig->params [n];
7622         cfg->arg_types = param_types;
7623
7624         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7625         if (cfg->method == method) {
7626
7627                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7628                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7629
7630                 /* ENTRY BLOCK */
7631                 NEW_BBLOCK (cfg, start_bblock);
7632                 cfg->bb_entry = start_bblock;
7633                 start_bblock->cil_code = NULL;
7634                 start_bblock->cil_length = 0;
7635
7636                 /* EXIT BLOCK */
7637                 NEW_BBLOCK (cfg, end_bblock);
7638                 cfg->bb_exit = end_bblock;
7639                 end_bblock->cil_code = NULL;
7640                 end_bblock->cil_length = 0;
7641                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7642                 g_assert (cfg->num_bblocks == 2);
7643
7644                 arg_array = cfg->args;
7645
7646                 if (header->num_clauses) {
7647                         cfg->spvars = g_hash_table_new (NULL, NULL);
7648                         cfg->exvars = g_hash_table_new (NULL, NULL);
7649                 }
7650                 /* handle exception clauses */
7651                 for (i = 0; i < header->num_clauses; ++i) {
7652                         MonoBasicBlock *try_bb;
7653                         MonoExceptionClause *clause = &header->clauses [i];
7654                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7655
7656                         try_bb->real_offset = clause->try_offset;
7657                         try_bb->try_start = TRUE;
7658                         try_bb->region = ((i + 1) << 8) | clause->flags;
7659                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7660                         tblock->real_offset = clause->handler_offset;
7661                         tblock->flags |= BB_EXCEPTION_HANDLER;
7662
7663                         /*
7664                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7665                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7666                          */
7667                         if (COMPILE_LLVM (cfg))
7668                                 link_bblock (cfg, try_bb, tblock);
7669
7670                         if (*(ip + clause->handler_offset) == CEE_POP)
7671                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7672
7673                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7674                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7675                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7676                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7677                                 MONO_ADD_INS (tblock, ins);
7678
7679                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
7680                                         /* finally clauses already have a seq point */
7681                                         /* seq points for filter clauses are emitted below */
7682                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7683                                         MONO_ADD_INS (tblock, ins);
7684                                 }
7685
7686                                 /* todo: is a fault block unsafe to optimize? */
7687                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7688                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7689                         }
7690
7691                         /*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);
7692                           while (p < end) {
7693                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7694                           }*/
7695                         /* catch and filter blocks get the exception object on the stack */
7696                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7697                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7698
7699                                 /* mostly like handle_stack_args (), but just sets the input args */
7700                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7701                                 tblock->in_scount = 1;
7702                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7703                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7704
7705                                 cfg->cbb = tblock;
7706
7707 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7708                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7709                                 if (!cfg->compile_llvm) {
7710                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7711                                         ins->dreg = tblock->in_stack [0]->dreg;
7712                                         MONO_ADD_INS (tblock, ins);
7713                                 }
7714 #else
7715                                 MonoInst *dummy_use;
7716
7717                                 /* 
7718                                  * Add a dummy use for the exvar so its liveness info will be
7719                                  * correct.
7720                                  */
7721                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7722 #endif
7723
7724                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7725                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7726                                         MONO_ADD_INS (tblock, ins);
7727                                 }
7728                                 
7729                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7730                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7731                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7732                                         tblock->real_offset = clause->data.filter_offset;
7733                                         tblock->in_scount = 1;
7734                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7735                                         /* The filter block shares the exvar with the handler block */
7736                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7737                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7738                                         MONO_ADD_INS (tblock, ins);
7739                                 }
7740                         }
7741
7742                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7743                                         clause->data.catch_class &&
7744                                         cfg->gshared &&
7745                                         mono_class_check_context_used (clause->data.catch_class)) {
7746                                 /*
7747                                  * In shared generic code with catch
7748                                  * clauses containing type variables
7749                                  * the exception handling code has to
7750                                  * be able to get to the rgctx.
7751                                  * Therefore we have to make sure that
7752                                  * the vtable/mrgctx argument (for
7753                                  * static or generic methods) or the
7754                                  * "this" argument (for non-static
7755                                  * methods) are live.
7756                                  */
7757                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7758                                                 mini_method_get_context (method)->method_inst ||
7759                                                 method->klass->valuetype) {
7760                                         mono_get_vtable_var (cfg);
7761                                 } else {
7762                                         MonoInst *dummy_use;
7763
7764                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7765                                 }
7766                         }
7767                 }
7768         } else {
7769                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7770                 cfg->cbb = start_bblock;
7771                 cfg->args = arg_array;
7772                 mono_save_args (cfg, sig, inline_args);
7773         }
7774
7775         /* FIRST CODE BLOCK */
7776         NEW_BBLOCK (cfg, tblock);
7777         tblock->cil_code = ip;
7778         cfg->cbb = tblock;
7779         cfg->ip = ip;
7780
7781         ADD_BBLOCK (cfg, tblock);
7782
7783         if (cfg->method == method) {
7784                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7785                 if (breakpoint_id) {
7786                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7787                         MONO_ADD_INS (cfg->cbb, ins);
7788                 }
7789         }
7790
7791         /* we use a separate basic block for the initialization code */
7792         NEW_BBLOCK (cfg, init_localsbb);
7793         if (cfg->method == method)
7794                 cfg->bb_init = init_localsbb;
7795         init_localsbb->real_offset = cfg->real_offset;
7796         start_bblock->next_bb = init_localsbb;
7797         init_localsbb->next_bb = cfg->cbb;
7798         link_bblock (cfg, start_bblock, init_localsbb);
7799         link_bblock (cfg, init_localsbb, cfg->cbb);
7800                 
7801         cfg->cbb = init_localsbb;
7802
7803         if (cfg->gsharedvt && cfg->method == method) {
7804                 MonoGSharedVtMethodInfo *info;
7805                 MonoInst *var, *locals_var;
7806                 int dreg;
7807
7808                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7809                 info->method = cfg->method;
7810                 info->count_entries = 16;
7811                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7812                 cfg->gsharedvt_info = info;
7813
7814                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7815                 /* prevent it from being register allocated */
7816                 //var->flags |= MONO_INST_VOLATILE;
7817                 cfg->gsharedvt_info_var = var;
7818
7819                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7820                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7821
7822                 /* Allocate locals */
7823                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7824                 /* prevent it from being register allocated */
7825                 //locals_var->flags |= MONO_INST_VOLATILE;
7826                 cfg->gsharedvt_locals_var = locals_var;
7827
7828                 dreg = alloc_ireg (cfg);
7829                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7830
7831                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7832                 ins->dreg = locals_var->dreg;
7833                 ins->sreg1 = dreg;
7834                 MONO_ADD_INS (cfg->cbb, ins);
7835                 cfg->gsharedvt_locals_var_ins = ins;
7836                 
7837                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7838                 /*
7839                 if (init_locals)
7840                         ins->flags |= MONO_INST_INIT;
7841                 */
7842         }
7843
7844         if (mono_security_core_clr_enabled ()) {
7845                 /* check if this is native code, e.g. an icall or a p/invoke */
7846                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7847                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7848                         if (wrapped) {
7849                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7850                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7851
7852                                 /* if this ia a native call then it can only be JITted from platform code */
7853                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7854                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7855                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7856                                                         mono_get_exception_method_access ();
7857                                                 emit_throw_exception (cfg, ex);
7858                                         }
7859                                 }
7860                         }
7861                 }
7862         }
7863
7864         CHECK_CFG_EXCEPTION;
7865
7866         if (header->code_size == 0)
7867                 UNVERIFIED;
7868
7869         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7870                 ip = err_pos;
7871                 UNVERIFIED;
7872         }
7873
7874         if (cfg->method == method)
7875                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
7876
7877         for (n = 0; n < header->num_locals; ++n) {
7878                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7879                         UNVERIFIED;
7880         }
7881         class_inits = NULL;
7882
7883         /* We force the vtable variable here for all shared methods
7884            for the possibility that they might show up in a stack
7885            trace where their exact instantiation is needed. */
7886         if (cfg->gshared && method == cfg->method) {
7887                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7888                                 mini_method_get_context (method)->method_inst ||
7889                                 method->klass->valuetype) {
7890                         mono_get_vtable_var (cfg);
7891                 } else {
7892                         /* FIXME: Is there a better way to do this?
7893                            We need the variable live for the duration
7894                            of the whole method. */
7895                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7896                 }
7897         }
7898
7899         /* add a check for this != NULL to inlined methods */
7900         if (is_virtual_call) {
7901                 MonoInst *arg_ins;
7902
7903                 NEW_ARGLOAD (cfg, arg_ins, 0);
7904                 MONO_ADD_INS (cfg->cbb, arg_ins);
7905                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7906         }
7907
7908         skip_dead_blocks = !dont_verify;
7909         if (skip_dead_blocks) {
7910                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
7911                 CHECK_CFG_ERROR;
7912                 g_assert (bb);
7913         }
7914
7915         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7916         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7917
7918         ins_flag = 0;
7919         start_new_bblock = 0;
7920         while (ip < end) {
7921                 if (cfg->method == method)
7922                         cfg->real_offset = ip - header->code;
7923                 else
7924                         cfg->real_offset = inline_offset;
7925                 cfg->ip = ip;
7926
7927                 context_used = 0;
7928
7929                 if (start_new_bblock) {
7930                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
7931                         if (start_new_bblock == 2) {
7932                                 g_assert (ip == tblock->cil_code);
7933                         } else {
7934                                 GET_BBLOCK (cfg, tblock, ip);
7935                         }
7936                         cfg->cbb->next_bb = tblock;
7937                         cfg->cbb = tblock;
7938                         start_new_bblock = 0;
7939                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
7940                                 if (cfg->verbose_level > 3)
7941                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7942                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7943                                 *sp++ = ins;
7944                         }
7945                         if (class_inits)
7946                                 g_slist_free (class_inits);
7947                         class_inits = NULL;
7948                 } else {
7949                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
7950                                 link_bblock (cfg, cfg->cbb, tblock);
7951                                 if (sp != stack_start) {
7952                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7953                                         sp = stack_start;
7954                                         CHECK_UNVERIFIABLE (cfg);
7955                                 }
7956                                 cfg->cbb->next_bb = tblock;
7957                                 cfg->cbb = tblock;
7958                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
7959                                         if (cfg->verbose_level > 3)
7960                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7961                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7962                                         *sp++ = ins;
7963                                 }
7964                                 g_slist_free (class_inits);
7965                                 class_inits = NULL;
7966                         }
7967                 }
7968
7969                 if (skip_dead_blocks) {
7970                         int ip_offset = ip - header->code;
7971
7972                         if (ip_offset == bb->end)
7973                                 bb = bb->next;
7974
7975                         if (bb->dead) {
7976                                 int op_size = mono_opcode_size (ip, end);
7977                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7978
7979                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7980
7981                                 if (ip_offset + op_size == bb->end) {
7982                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7983                                         MONO_ADD_INS (cfg->cbb, ins);
7984                                         start_new_bblock = 1;
7985                                 }
7986
7987                                 ip += op_size;
7988                                 continue;
7989                         }
7990                 }
7991                 /*
7992                  * Sequence points are points where the debugger can place a breakpoint.
7993                  * Currently, we generate these automatically at points where the IL
7994                  * stack is empty.
7995                  */
7996                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7997                         /*
7998                          * Make methods interruptable at the beginning, and at the targets of
7999                          * backward branches.
8000                          * Also, do this at the start of every bblock in methods with clauses too,
8001                          * to be able to handle instructions with inprecise control flow like
8002                          * throw/endfinally.
8003                          * Backward branches are handled at the end of method-to-ir ().
8004                          */
8005                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8006                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8007
8008                         /* Avoid sequence points on empty IL like .volatile */
8009                         // FIXME: Enable this
8010                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8011                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8012                         if ((sp != stack_start) && !sym_seq_point)
8013                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8014                         MONO_ADD_INS (cfg->cbb, ins);
8015
8016                         if (sym_seq_points)
8017                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8018                 }
8019
8020                 cfg->cbb->real_offset = cfg->real_offset;
8021
8022                 if ((cfg->method == method) && cfg->coverage_info) {
8023                         guint32 cil_offset = ip - header->code;
8024                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8025
8026                         /* TODO: Use an increment here */
8027 #if defined(TARGET_X86)
8028                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8029                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8030                         ins->inst_imm = 1;
8031                         MONO_ADD_INS (cfg->cbb, ins);
8032 #else
8033                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8034                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8035 #endif
8036                 }
8037
8038                 if (cfg->verbose_level > 3)
8039                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8040
8041                 switch (*ip) {
8042                 case CEE_NOP:
8043                         if (seq_points && !sym_seq_points && sp != stack_start) {
8044                                 /*
8045                                  * The C# compiler uses these nops to notify the JIT that it should
8046                                  * insert seq points.
8047                                  */
8048                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8049                                 MONO_ADD_INS (cfg->cbb, ins);
8050                         }
8051                         if (cfg->keep_cil_nops)
8052                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8053                         else
8054                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8055                         ip++;
8056                         MONO_ADD_INS (cfg->cbb, ins);
8057                         break;
8058                 case CEE_BREAK:
8059                         if (should_insert_brekpoint (cfg->method)) {
8060                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8061                         } else {
8062                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8063                         }
8064                         ip++;
8065                         MONO_ADD_INS (cfg->cbb, ins);
8066                         break;
8067                 case CEE_LDARG_0:
8068                 case CEE_LDARG_1:
8069                 case CEE_LDARG_2:
8070                 case CEE_LDARG_3:
8071                         CHECK_STACK_OVF (1);
8072                         n = (*ip)-CEE_LDARG_0;
8073                         CHECK_ARG (n);
8074                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8075                         ip++;
8076                         *sp++ = ins;
8077                         break;
8078                 case CEE_LDLOC_0:
8079                 case CEE_LDLOC_1:
8080                 case CEE_LDLOC_2:
8081                 case CEE_LDLOC_3:
8082                         CHECK_STACK_OVF (1);
8083                         n = (*ip)-CEE_LDLOC_0;
8084                         CHECK_LOCAL (n);
8085                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8086                         ip++;
8087                         *sp++ = ins;
8088                         break;
8089                 case CEE_STLOC_0:
8090                 case CEE_STLOC_1:
8091                 case CEE_STLOC_2:
8092                 case CEE_STLOC_3: {
8093                         CHECK_STACK (1);
8094                         n = (*ip)-CEE_STLOC_0;
8095                         CHECK_LOCAL (n);
8096                         --sp;
8097                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8098                                 UNVERIFIED;
8099                         emit_stloc_ir (cfg, sp, header, n);
8100                         ++ip;
8101                         inline_costs += 1;
8102                         break;
8103                         }
8104                 case CEE_LDARG_S:
8105                         CHECK_OPSIZE (2);
8106                         CHECK_STACK_OVF (1);
8107                         n = ip [1];
8108                         CHECK_ARG (n);
8109                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8110                         *sp++ = ins;
8111                         ip += 2;
8112                         break;
8113                 case CEE_LDARGA_S:
8114                         CHECK_OPSIZE (2);
8115                         CHECK_STACK_OVF (1);
8116                         n = ip [1];
8117                         CHECK_ARG (n);
8118                         NEW_ARGLOADA (cfg, ins, n);
8119                         MONO_ADD_INS (cfg->cbb, ins);
8120                         *sp++ = ins;
8121                         ip += 2;
8122                         break;
8123                 case CEE_STARG_S:
8124                         CHECK_OPSIZE (2);
8125                         CHECK_STACK (1);
8126                         --sp;
8127                         n = ip [1];
8128                         CHECK_ARG (n);
8129                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8130                                 UNVERIFIED;
8131                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8132                         ip += 2;
8133                         break;
8134                 case CEE_LDLOC_S:
8135                         CHECK_OPSIZE (2);
8136                         CHECK_STACK_OVF (1);
8137                         n = ip [1];
8138                         CHECK_LOCAL (n);
8139                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8140                         *sp++ = ins;
8141                         ip += 2;
8142                         break;
8143                 case CEE_LDLOCA_S: {
8144                         unsigned char *tmp_ip;
8145                         CHECK_OPSIZE (2);
8146                         CHECK_STACK_OVF (1);
8147                         CHECK_LOCAL (ip [1]);
8148
8149                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8150                                 ip = tmp_ip;
8151                                 inline_costs += 1;
8152                                 break;
8153                         }
8154
8155                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8156                         *sp++ = ins;
8157                         ip += 2;
8158                         break;
8159                 }
8160                 case CEE_STLOC_S:
8161                         CHECK_OPSIZE (2);
8162                         CHECK_STACK (1);
8163                         --sp;
8164                         CHECK_LOCAL (ip [1]);
8165                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8166                                 UNVERIFIED;
8167                         emit_stloc_ir (cfg, sp, header, ip [1]);
8168                         ip += 2;
8169                         inline_costs += 1;
8170                         break;
8171                 case CEE_LDNULL:
8172                         CHECK_STACK_OVF (1);
8173                         EMIT_NEW_PCONST (cfg, ins, NULL);
8174                         ins->type = STACK_OBJ;
8175                         ++ip;
8176                         *sp++ = ins;
8177                         break;
8178                 case CEE_LDC_I4_M1:
8179                         CHECK_STACK_OVF (1);
8180                         EMIT_NEW_ICONST (cfg, ins, -1);
8181                         ++ip;
8182                         *sp++ = ins;
8183                         break;
8184                 case CEE_LDC_I4_0:
8185                 case CEE_LDC_I4_1:
8186                 case CEE_LDC_I4_2:
8187                 case CEE_LDC_I4_3:
8188                 case CEE_LDC_I4_4:
8189                 case CEE_LDC_I4_5:
8190                 case CEE_LDC_I4_6:
8191                 case CEE_LDC_I4_7:
8192                 case CEE_LDC_I4_8:
8193                         CHECK_STACK_OVF (1);
8194                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8195                         ++ip;
8196                         *sp++ = ins;
8197                         break;
8198                 case CEE_LDC_I4_S:
8199                         CHECK_OPSIZE (2);
8200                         CHECK_STACK_OVF (1);
8201                         ++ip;
8202                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8203                         ++ip;
8204                         *sp++ = ins;
8205                         break;
8206                 case CEE_LDC_I4:
8207                         CHECK_OPSIZE (5);
8208                         CHECK_STACK_OVF (1);
8209                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8210                         ip += 5;
8211                         *sp++ = ins;
8212                         break;
8213                 case CEE_LDC_I8:
8214                         CHECK_OPSIZE (9);
8215                         CHECK_STACK_OVF (1);
8216                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8217                         ins->type = STACK_I8;
8218                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8219                         ++ip;
8220                         ins->inst_l = (gint64)read64 (ip);
8221                         MONO_ADD_INS (cfg->cbb, ins);
8222                         ip += 8;
8223                         *sp++ = ins;
8224                         break;
8225                 case CEE_LDC_R4: {
8226                         float *f;
8227                         gboolean use_aotconst = FALSE;
8228
8229 #ifdef TARGET_POWERPC
8230                         /* FIXME: Clean this up */
8231                         if (cfg->compile_aot)
8232                                 use_aotconst = TRUE;
8233 #endif
8234
8235                         /* FIXME: we should really allocate this only late in the compilation process */
8236                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8237                         CHECK_OPSIZE (5);
8238                         CHECK_STACK_OVF (1);
8239
8240                         if (use_aotconst) {
8241                                 MonoInst *cons;
8242                                 int dreg;
8243
8244                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8245
8246                                 dreg = alloc_freg (cfg);
8247                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8248                                 ins->type = cfg->r4_stack_type;
8249                         } else {
8250                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8251                                 ins->type = cfg->r4_stack_type;
8252                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8253                                 ins->inst_p0 = f;
8254                                 MONO_ADD_INS (cfg->cbb, ins);
8255                         }
8256                         ++ip;
8257                         readr4 (ip, f);
8258                         ip += 4;
8259                         *sp++ = ins;                    
8260                         break;
8261                 }
8262                 case CEE_LDC_R8: {
8263                         double *d;
8264                         gboolean use_aotconst = FALSE;
8265
8266 #ifdef TARGET_POWERPC
8267                         /* FIXME: Clean this up */
8268                         if (cfg->compile_aot)
8269                                 use_aotconst = TRUE;
8270 #endif
8271
8272                         /* FIXME: we should really allocate this only late in the compilation process */
8273                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8274                         CHECK_OPSIZE (9);
8275                         CHECK_STACK_OVF (1);
8276
8277                         if (use_aotconst) {
8278                                 MonoInst *cons;
8279                                 int dreg;
8280
8281                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8282
8283                                 dreg = alloc_freg (cfg);
8284                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8285                                 ins->type = STACK_R8;
8286                         } else {
8287                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8288                                 ins->type = STACK_R8;
8289                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8290                                 ins->inst_p0 = d;
8291                                 MONO_ADD_INS (cfg->cbb, ins);
8292                         }
8293                         ++ip;
8294                         readr8 (ip, d);
8295                         ip += 8;
8296                         *sp++ = ins;
8297                         break;
8298                 }
8299                 case CEE_DUP: {
8300                         MonoInst *temp, *store;
8301                         CHECK_STACK (1);
8302                         CHECK_STACK_OVF (1);
8303                         sp--;
8304                         ins = *sp;
8305
8306                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8307                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8308
8309                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8310                         *sp++ = ins;
8311
8312                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8313                         *sp++ = ins;
8314
8315                         ++ip;
8316                         inline_costs += 2;
8317                         break;
8318                 }
8319                 case CEE_POP:
8320                         CHECK_STACK (1);
8321                         ip++;
8322                         --sp;
8323
8324 #ifdef TARGET_X86
8325                         if (sp [0]->type == STACK_R8)
8326                                 /* we need to pop the value from the x86 FP stack */
8327                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8328 #endif
8329                         break;
8330                 case CEE_JMP: {
8331                         MonoCallInst *call;
8332                         MonoMethodSignature *fsig;
8333                         int i, n;
8334
8335                         INLINE_FAILURE ("jmp");
8336                         GSHAREDVT_FAILURE (*ip);
8337
8338                         CHECK_OPSIZE (5);
8339                         if (stack_start != sp)
8340                                 UNVERIFIED;
8341                         token = read32 (ip + 1);
8342                         /* FIXME: check the signature matches */
8343                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8344                         CHECK_CFG_ERROR;
8345  
8346                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8347                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8348
8349                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8350
8351                         fsig = mono_method_signature (cmethod);
8352                         n = fsig->param_count + fsig->hasthis;
8353                         if (cfg->llvm_only) {
8354                                 MonoInst **args;
8355
8356                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8357                                 for (i = 0; i < n; ++i)
8358                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8359                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8360                                 /*
8361                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8362                                  * have to emit a normal return since llvm expects it.
8363                                  */
8364                                 if (cfg->ret)
8365                                         emit_setret (cfg, ins);
8366                                 MONO_INST_NEW (cfg, ins, OP_BR);
8367                                 ins->inst_target_bb = end_bblock;
8368                                 MONO_ADD_INS (cfg->cbb, ins);
8369                                 link_bblock (cfg, cfg->cbb, end_bblock);
8370                                 ip += 5;
8371                                 break;
8372                         } else if (cfg->backend->have_op_tail_call) {
8373                                 /* Handle tail calls similarly to calls */
8374                                 DISABLE_AOT (cfg);
8375
8376                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8377                                 call->method = cmethod;
8378                                 call->tail_call = TRUE;
8379                                 call->signature = mono_method_signature (cmethod);
8380                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8381                                 call->inst.inst_p0 = cmethod;
8382                                 for (i = 0; i < n; ++i)
8383                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8384
8385                                 if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
8386                                         call->vret_var = cfg->vret_addr;
8387
8388                                 mono_arch_emit_call (cfg, call);
8389                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8390                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8391                         } else {
8392                                 for (i = 0; i < num_args; ++i)
8393                                         /* Prevent arguments from being optimized away */
8394                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8395
8396                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8397                                 ins = (MonoInst*)call;
8398                                 ins->inst_p0 = cmethod;
8399                                 MONO_ADD_INS (cfg->cbb, ins);
8400                         }
8401
8402                         ip += 5;
8403                         start_new_bblock = 1;
8404                         break;
8405                 }
8406                 case CEE_CALLI: {
8407                         MonoInst *addr;
8408                         MonoMethodSignature *fsig;
8409
8410                         CHECK_OPSIZE (5);
8411                         token = read32 (ip + 1);
8412
8413                         ins = NULL;
8414
8415                         //GSHAREDVT_FAILURE (*ip);
8416                         cmethod = NULL;
8417                         CHECK_STACK (1);
8418                         --sp;
8419                         addr = *sp;
8420                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
8421                         CHECK_CFG_ERROR;
8422
8423                         if (method->dynamic && fsig->pinvoke) {
8424                                 MonoInst *args [3];
8425
8426                                 /*
8427                                  * This is a call through a function pointer using a pinvoke
8428                                  * signature. Have to create a wrapper and call that instead.
8429                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8430                                  * instead based on the signature.
8431                                  */
8432                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8433                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8434                                 args [2] = addr;
8435                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8436                         }
8437
8438                         n = fsig->param_count + fsig->hasthis;
8439
8440                         CHECK_STACK (n);
8441
8442                         //g_assert (!virtual_ || fsig->hasthis);
8443
8444                         sp -= n;
8445
8446                         inline_costs += 10 * num_calls++;
8447
8448                         /*
8449                          * Making generic calls out of gsharedvt methods.
8450                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8451                          * patching gshared method addresses into a gsharedvt method.
8452                          */
8453                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8454                                 /*
8455                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8456                                  */
8457                                 MonoInst *callee = addr;
8458
8459                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8460                                         /* Not tested */
8461                                         GSHAREDVT_FAILURE (*ip);
8462
8463                                 if (cfg->llvm_only)
8464                                         // FIXME:
8465                                         GSHAREDVT_FAILURE (*ip);
8466
8467                                 addr = emit_get_rgctx_sig (cfg, context_used,
8468                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8469                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8470                                 goto calli_end;
8471                         }
8472
8473                         /* Prevent inlining of methods with indirect calls */
8474                         INLINE_FAILURE ("indirect call");
8475
8476                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8477                                 MonoJumpInfoType info_type;
8478                                 gpointer info_data;
8479
8480                                 /*
8481                                  * Instead of emitting an indirect call, emit a direct call
8482                                  * with the contents of the aotconst as the patch info.
8483                                  */
8484                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8485                                         info_type = (MonoJumpInfoType)addr->inst_c1;
8486                                         info_data = addr->inst_p0;
8487                                 } else {
8488                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
8489                                         info_data = addr->inst_right->inst_left;
8490                                 }
8491
8492                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
8493                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
8494                                         NULLIFY_INS (addr);
8495                                         goto calli_end;
8496                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8497                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8498                                         NULLIFY_INS (addr);
8499                                         goto calli_end;
8500                                 }
8501                         }
8502                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8503
8504                         calli_end:
8505
8506                         /* End of call, INS should contain the result of the call, if any */
8507
8508                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8509                                 g_assert (ins);
8510                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8511                         }
8512
8513                         CHECK_CFG_EXCEPTION;
8514
8515                         ip += 5;
8516                         ins_flag = 0;
8517                         constrained_class = NULL;
8518                         break;
8519                 }
8520                 case CEE_CALL:
8521                 case CEE_CALLVIRT: {
8522                         MonoInst *addr = NULL;
8523                         MonoMethodSignature *fsig = NULL;
8524                         int array_rank = 0;
8525                         int virtual_ = *ip == CEE_CALLVIRT;
8526                         gboolean pass_imt_from_rgctx = FALSE;
8527                         MonoInst *imt_arg = NULL;
8528                         MonoInst *keep_this_alive = NULL;
8529                         gboolean pass_vtable = FALSE;
8530                         gboolean pass_mrgctx = FALSE;
8531                         MonoInst *vtable_arg = NULL;
8532                         gboolean check_this = FALSE;
8533                         gboolean supported_tail_call = FALSE;
8534                         gboolean tail_call = FALSE;
8535                         gboolean need_seq_point = FALSE;
8536                         guint32 call_opcode = *ip;
8537                         gboolean emit_widen = TRUE;
8538                         gboolean push_res = TRUE;
8539                         gboolean skip_ret = FALSE;
8540                         gboolean delegate_invoke = FALSE;
8541                         gboolean direct_icall = FALSE;
8542                         gboolean constrained_partial_call = FALSE;
8543                         MonoMethod *cil_method;
8544
8545                         CHECK_OPSIZE (5);
8546                         token = read32 (ip + 1);
8547
8548                         ins = NULL;
8549
8550                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8551                         CHECK_CFG_ERROR;
8552
8553                         cil_method = cmethod;
8554                                 
8555                         if (constrained_class) {
8556                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8557                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8558                                                 g_assert (!cmethod->klass->valuetype);
8559                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8560                                                         constrained_partial_call = TRUE;
8561                                         }
8562                                 }
8563
8564                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8565                                         if (cfg->verbose_level > 2)
8566                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8567                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8568                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8569                                                   cfg->gshared)) {
8570                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8571                                                 CHECK_CFG_ERROR;
8572                                         }
8573                                 } else {
8574                                         if (cfg->verbose_level > 2)
8575                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8576
8577                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8578                                                 /* 
8579                                                  * This is needed since get_method_constrained can't find 
8580                                                  * the method in klass representing a type var.
8581                                                  * The type var is guaranteed to be a reference type in this
8582                                                  * case.
8583                                                  */
8584                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8585                                                         g_assert (!cmethod->klass->valuetype);
8586                                         } else {
8587                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8588                                                 CHECK_CFG_ERROR;
8589                                         }
8590                                 }
8591
8592                                 if (constrained_class->enumtype && !strcmp (cmethod->name, "GetHashCode")) {
8593                                         /* Use the corresponding method from the base type to avoid boxing */
8594                                         MonoType *base_type = mono_class_enum_basetype (constrained_class);
8595                                         g_assert (base_type);
8596                                         constrained_class = mono_class_from_mono_type (base_type);
8597                                         cmethod = mono_class_get_method_from_name (constrained_class, cmethod->name, 0);
8598                                         g_assert (cmethod);
8599                                 }
8600                         }
8601                                         
8602                         if (!dont_verify && !cfg->skip_visibility) {
8603                                 MonoMethod *target_method = cil_method;
8604                                 if (method->is_inflated) {
8605                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
8606                                         CHECK_CFG_ERROR;
8607                                 }
8608                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8609                                         !mono_method_can_access_method (method, cil_method))
8610                                         emit_method_access_failure (cfg, method, cil_method);
8611                         }
8612
8613                         if (mono_security_core_clr_enabled ())
8614                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8615
8616                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8617                                 /* MS.NET seems to silently convert this to a callvirt */
8618                                 virtual_ = 1;
8619
8620                         {
8621                                 /*
8622                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8623                                  * converts to a callvirt.
8624                                  *
8625                                  * tests/bug-515884.il is an example of this behavior
8626                                  */
8627                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8628                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8629                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8630                                         virtual_ = 1;
8631                         }
8632
8633                         if (!cmethod->klass->inited)
8634                                 if (!mono_class_init (cmethod->klass))
8635                                         TYPE_LOAD_ERROR (cmethod->klass);
8636
8637                         fsig = mono_method_signature (cmethod);
8638                         if (!fsig)
8639                                 LOAD_ERROR;
8640                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8641                                 mini_class_is_system_array (cmethod->klass)) {
8642                                 array_rank = cmethod->klass->rank;
8643                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8644                                 direct_icall = TRUE;
8645                         } else if (fsig->pinvoke) {
8646                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8647                                 fsig = mono_method_signature (wrapper);
8648                         } else if (constrained_class) {
8649                         } else {
8650                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8651                                 CHECK_CFG_ERROR;
8652                         }
8653
8654                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
8655                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
8656
8657                         /* See code below */
8658                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8659                                 MonoBasicBlock *tbb;
8660
8661                                 GET_BBLOCK (cfg, tbb, ip + 5);
8662                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8663                                         /*
8664                                          * We want to extend the try block to cover the call, but we can't do it if the
8665                                          * call is made directly since its followed by an exception check.
8666                                          */
8667                                         direct_icall = FALSE;
8668                                 }
8669                         }
8670
8671                         mono_save_token_info (cfg, image, token, cil_method);
8672
8673                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8674                                 need_seq_point = TRUE;
8675
8676                         /* Don't support calls made using type arguments for now */
8677                         /*
8678                           if (cfg->gsharedvt) {
8679                           if (mini_is_gsharedvt_signature (fsig))
8680                           GSHAREDVT_FAILURE (*ip);
8681                           }
8682                         */
8683
8684                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8685                                 g_assert_not_reached ();
8686
8687                         n = fsig->param_count + fsig->hasthis;
8688
8689                         if (!cfg->gshared && mono_class_is_gtd (cmethod->klass))
8690                                 UNVERIFIED;
8691
8692                         if (!cfg->gshared)
8693                                 g_assert (!mono_method_check_context_used (cmethod));
8694
8695                         CHECK_STACK (n);
8696
8697                         //g_assert (!virtual_ || fsig->hasthis);
8698
8699                         sp -= n;
8700
8701                         /*
8702                          * We have the `constrained.' prefix opcode.
8703                          */
8704                         if (constrained_class) {
8705                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8706                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8707                                                 /* The 'Own method' case below */
8708                                         } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) {
8709                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8710                                         } else {
8711                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8712                                                 CHECK_CFG_EXCEPTION;
8713                                                 g_assert (ins);
8714                                                 goto call_end;
8715                                         }
8716                                 }
8717
8718                                 if (constrained_partial_call) {
8719                                         gboolean need_box = TRUE;
8720
8721                                         /*
8722                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8723                                          * called method is not known at compile time either. The called method could end up being
8724                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8725                                          * to box the receiver.
8726                                          * A simple solution would be to box always and make a normal virtual call, but that would
8727                                          * be bad performance wise.
8728                                          */
8729                                         if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) {
8730                                                 /*
8731                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8732                                                  */
8733                                                 need_box = FALSE;
8734                                         }
8735
8736                                         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)) {
8737                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8738                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8739                                                 ins->klass = constrained_class;
8740                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8741                                                 CHECK_CFG_EXCEPTION;
8742                                         } else if (need_box) {
8743                                                 MonoInst *box_type;
8744                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8745                                                 MonoInst *nonbox_call;
8746
8747                                                 /*
8748                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8749                                                  * if needed.
8750                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8751                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8752                                                  */
8753                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8754
8755                                                 NEW_BBLOCK (cfg, is_ref_bb);
8756                                                 NEW_BBLOCK (cfg, end_bb);
8757
8758                                                 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);
8759                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
8760                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
8761
8762                                                 /* Non-ref case */
8763                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8764
8765                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8766
8767                                                 /* Ref case */
8768                                                 MONO_START_BB (cfg, is_ref_bb);
8769                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8770                                                 ins->klass = constrained_class;
8771                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8772                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8773
8774                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8775
8776                                                 MONO_START_BB (cfg, end_bb);
8777                                                 cfg->cbb = end_bb;
8778
8779                                                 nonbox_call->dreg = ins->dreg;
8780                                                 goto call_end;
8781                                         } else {
8782                                                 g_assert (mono_class_is_interface (cmethod->klass));
8783                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8784                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8785                                                 goto call_end;
8786                                         }
8787                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8788                                         /*
8789                                          * The type parameter is instantiated as a valuetype,
8790                                          * but that type doesn't override the method we're
8791                                          * calling, so we need to box `this'.
8792                                          */
8793                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8794                                         ins->klass = constrained_class;
8795                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8796                                         CHECK_CFG_EXCEPTION;
8797                                 } else if (!constrained_class->valuetype) {
8798                                         int dreg = alloc_ireg_ref (cfg);
8799
8800                                         /*
8801                                          * The type parameter is instantiated as a reference
8802                                          * type.  We have a managed pointer on the stack, so
8803                                          * we need to dereference it here.
8804                                          */
8805                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8806                                         ins->type = STACK_OBJ;
8807                                         sp [0] = ins;
8808                                 } else {
8809                                         if (cmethod->klass->valuetype) {
8810                                                 /* Own method */
8811                                         } else {
8812                                                 /* Interface method */
8813                                                 int ioffset, slot;
8814
8815                                                 mono_class_setup_vtable (constrained_class);
8816                                                 CHECK_TYPELOAD (constrained_class);
8817                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8818                                                 if (ioffset == -1)
8819                                                         TYPE_LOAD_ERROR (constrained_class);
8820                                                 slot = mono_method_get_vtable_slot (cmethod);
8821                                                 if (slot == -1)
8822                                                         TYPE_LOAD_ERROR (cmethod->klass);
8823                                                 cmethod = constrained_class->vtable [ioffset + slot];
8824
8825                                                 if (cmethod->klass == mono_defaults.enum_class) {
8826                                                         /* Enum implements some interfaces, so treat this as the first case */
8827                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8828                                                         ins->klass = constrained_class;
8829                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8830                                                         CHECK_CFG_EXCEPTION;
8831                                                 }
8832                                         }
8833                                         virtual_ = 0;
8834                                 }
8835                                 constrained_class = NULL;
8836                         }
8837
8838                         if (check_call_signature (cfg, fsig, sp))
8839                                 UNVERIFIED;
8840
8841                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8842                                 delegate_invoke = TRUE;
8843
8844                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8845                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8846                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8847                                         emit_widen = FALSE;
8848                                 }
8849
8850                                 goto call_end;
8851                         }
8852
8853                         /* 
8854                          * If the callee is a shared method, then its static cctor
8855                          * might not get called after the call was patched.
8856                          */
8857                         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)) {
8858                                 emit_class_init (cfg, cmethod->klass);
8859                                 CHECK_TYPELOAD (cmethod->klass);
8860                         }
8861
8862                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8863
8864                         if (cfg->gshared) {
8865                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8866
8867                                 context_used = mini_method_check_context_used (cfg, cmethod);
8868
8869                                 if (context_used && mono_class_is_interface (cmethod->klass)) {
8870                                         /* Generic method interface
8871                                            calls are resolved via a
8872                                            helper function and don't
8873                                            need an imt. */
8874                                         if (!cmethod_context || !cmethod_context->method_inst)
8875                                                 pass_imt_from_rgctx = TRUE;
8876                                 }
8877
8878                                 /*
8879                                  * If a shared method calls another
8880                                  * shared method then the caller must
8881                                  * have a generic sharing context
8882                                  * because the magic trampoline
8883                                  * requires it.  FIXME: We shouldn't
8884                                  * have to force the vtable/mrgctx
8885                                  * variable here.  Instead there
8886                                  * should be a flag in the cfg to
8887                                  * request a generic sharing context.
8888                                  */
8889                                 if (context_used &&
8890                                                 ((cfg->method->flags & METHOD_ATTRIBUTE_STATIC) || cfg->method->klass->valuetype))
8891                                         mono_get_vtable_var (cfg);
8892                         }
8893
8894                         if (pass_vtable) {
8895                                 if (context_used) {
8896                                         vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8897                                 } else {
8898                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8899
8900                                         CHECK_TYPELOAD (cmethod->klass);
8901                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8902                                 }
8903                         }
8904
8905                         if (pass_mrgctx) {
8906                                 g_assert (!vtable_arg);
8907
8908                                 if (!cfg->compile_aot) {
8909                                         /* 
8910                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8911                                          * for type load errors before.
8912                                          */
8913                                         mono_class_setup_vtable (cmethod->klass);
8914                                         CHECK_TYPELOAD (cmethod->klass);
8915                                 }
8916
8917                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8918
8919                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8920                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8921                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8922                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8923                                         if (virtual_)
8924                                                 check_this = TRUE;
8925                                         virtual_ = 0;
8926                                 }
8927                         }
8928
8929                         if (pass_imt_from_rgctx) {
8930                                 g_assert (!pass_vtable);
8931
8932                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8933                                         cmethod, MONO_RGCTX_INFO_METHOD);
8934                         }
8935
8936                         if (check_this)
8937                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8938
8939                         /* Calling virtual generic methods */
8940                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
8941                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8942                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8943                             fsig->generic_param_count && 
8944                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
8945                                 !cfg->llvm_only) {
8946                                 MonoInst *this_temp, *this_arg_temp, *store;
8947                                 MonoInst *iargs [4];
8948
8949                                 g_assert (fsig->is_inflated);
8950
8951                                 /* Prevent inlining of methods that contain indirect calls */
8952                                 INLINE_FAILURE ("virtual generic call");
8953
8954                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8955                                         GSHAREDVT_FAILURE (*ip);
8956
8957                                 if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
8958                                         g_assert (!imt_arg);
8959                                         if (!context_used)
8960                                                 g_assert (cmethod->is_inflated);
8961                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8962                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8963                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8964                                 } else {
8965                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8966                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8967                                         MONO_ADD_INS (cfg->cbb, store);
8968
8969                                         /* FIXME: This should be a managed pointer */
8970                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8971
8972                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8973                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8974                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8975                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8976                                         addr = mono_emit_jit_icall (cfg,
8977                                                                                                 mono_helper_compile_generic_method, iargs);
8978
8979                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8980
8981                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8982                                 }
8983
8984                                 goto call_end;
8985                         }
8986
8987                         /*
8988                          * Implement a workaround for the inherent races involved in locking:
8989                          * Monitor.Enter ()
8990                          * try {
8991                          * } finally {
8992                          *    Monitor.Exit ()
8993                          * }
8994                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8995                          * try block, the Exit () won't be executed, see:
8996                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8997                          * To work around this, we extend such try blocks to include the last x bytes
8998                          * of the Monitor.Enter () call.
8999                          */
9000                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9001                                 MonoBasicBlock *tbb;
9002
9003                                 GET_BBLOCK (cfg, tbb, ip + 5);
9004                                 /* 
9005                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9006                                  * from Monitor.Enter like ArgumentNullException.
9007                                  */
9008                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9009                                         /* Mark this bblock as needing to be extended */
9010                                         tbb->extend_try_block = TRUE;
9011                                 }
9012                         }
9013
9014                         /* Conversion to a JIT intrinsic */
9015                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9016                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9017                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9018                                         emit_widen = FALSE;
9019                                 }
9020                                 goto call_end;
9021                         }
9022                         CHECK_CFG_ERROR;
9023                         
9024                         /* Inlining */
9025                         if ((cfg->opt & MONO_OPT_INLINE) &&
9026                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9027                             mono_method_check_inlining (cfg, cmethod)) {
9028                                 int costs;
9029                                 gboolean always = FALSE;
9030
9031                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9032                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9033                                         /* Prevent inlining of methods that call wrappers */
9034                                         INLINE_FAILURE ("wrapper call");
9035                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9036                                         always = TRUE;
9037                                 }
9038
9039                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9040                                 if (costs) {
9041                                         cfg->real_offset += 5;
9042
9043                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9044                                                 /* *sp is already set by inline_method */
9045                                                 sp++;
9046                                                 push_res = FALSE;
9047                                         }
9048
9049                                         inline_costs += costs;
9050
9051                                         goto call_end;
9052                                 }
9053                         }
9054
9055                         /* Tail recursion elimination */
9056                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9057                                 gboolean has_vtargs = FALSE;
9058                                 int i;
9059
9060                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9061                                 INLINE_FAILURE ("tail call");
9062
9063                                 /* keep it simple */
9064                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9065                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9066                                                 has_vtargs = TRUE;
9067                                 }
9068
9069                                 if (!has_vtargs) {
9070                                         if (need_seq_point) {
9071                                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9072                                                 need_seq_point = FALSE;
9073                                         }
9074                                         for (i = 0; i < n; ++i)
9075                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9076                                         MONO_INST_NEW (cfg, ins, OP_BR);
9077                                         MONO_ADD_INS (cfg->cbb, ins);
9078                                         tblock = start_bblock->out_bb [0];
9079                                         link_bblock (cfg, cfg->cbb, tblock);
9080                                         ins->inst_target_bb = tblock;
9081                                         start_new_bblock = 1;
9082
9083                                         /* skip the CEE_RET, too */
9084                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9085                                                 skip_ret = TRUE;
9086                                         push_res = FALSE;
9087                                         goto call_end;
9088                                 }
9089                         }
9090
9091                         inline_costs += 10 * num_calls++;
9092
9093                         /*
9094                          * Synchronized wrappers.
9095                          * Its hard to determine where to replace a method with its synchronized
9096                          * wrapper without causing an infinite recursion. The current solution is
9097                          * to add the synchronized wrapper in the trampolines, and to
9098                          * change the called method to a dummy wrapper, and resolve that wrapper
9099                          * to the real method in mono_jit_compile_method ().
9100                          */
9101                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9102                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9103                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9104                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9105                         }
9106
9107                         /*
9108                          * Making generic calls out of gsharedvt methods.
9109                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9110                          * patching gshared method addresses into a gsharedvt method.
9111                          */
9112                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) &&
9113                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9114                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9115                                 MonoRgctxInfoType info_type;
9116
9117                                 if (virtual_) {
9118                                         //if (mono_class_is_interface (cmethod->klass))
9119                                                 //GSHAREDVT_FAILURE (*ip);
9120                                         // disable for possible remoting calls
9121                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9122                                                 GSHAREDVT_FAILURE (*ip);
9123                                         if (fsig->generic_param_count) {
9124                                                 /* virtual generic call */
9125                                                 g_assert (!imt_arg);
9126                                                 /* Same as the virtual generic case above */
9127                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9128                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9129                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9130                                                 vtable_arg = NULL;
9131                                         } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) {
9132                                                 /* This can happen when we call a fully instantiated iface method */
9133                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9134                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9135                                                 vtable_arg = NULL;
9136                                         }
9137                                 }
9138
9139                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9140                                         keep_this_alive = sp [0];
9141
9142                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9143                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9144                                 else
9145                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9146                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9147
9148                                 if (cfg->llvm_only) {
9149                                         // FIXME: Avoid initializing vtable_arg
9150                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9151                                 } else {
9152                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9153                                 }
9154                                 goto call_end;
9155                         }
9156
9157                         /* Generic sharing */
9158
9159                         /*
9160                          * Use this if the callee is gsharedvt sharable too, since
9161                          * at runtime we might find an instantiation so the call cannot
9162                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9163                          */
9164                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9165                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9166                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9167                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9168                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9169                                 INLINE_FAILURE ("gshared");
9170
9171                                 g_assert (cfg->gshared && cmethod);
9172                                 g_assert (!addr);
9173
9174                                 /*
9175                                  * We are compiling a call to a
9176                                  * generic method from shared code,
9177                                  * which means that we have to look up
9178                                  * the method in the rgctx and do an
9179                                  * indirect call.
9180                                  */
9181                                 if (fsig->hasthis)
9182                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9183
9184                                 if (cfg->llvm_only) {
9185                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9186                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9187                                         else
9188                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9189                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9190                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9191                                 } else {
9192                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9193                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9194                                 }
9195                                 goto call_end;
9196                         }
9197
9198                         /* Direct calls to icalls */
9199                         if (direct_icall) {
9200                                 MonoMethod *wrapper;
9201                                 int costs;
9202
9203                                 /* Inline the wrapper */
9204                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9205
9206                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9207                                 g_assert (costs > 0);
9208                                 cfg->real_offset += 5;
9209
9210                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9211                                         /* *sp is already set by inline_method */
9212                                         sp++;
9213                                         push_res = FALSE;
9214                                 }
9215
9216                                 inline_costs += costs;
9217
9218                                 goto call_end;
9219                         }
9220                                         
9221                         /* Array methods */
9222                         if (array_rank) {
9223                                 MonoInst *addr;
9224
9225                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9226                                         MonoInst *val = sp [fsig->param_count];
9227
9228                                         if (val->type == STACK_OBJ) {
9229                                                 MonoInst *iargs [2];
9230
9231                                                 iargs [0] = sp [0];
9232                                                 iargs [1] = val;
9233                                                 
9234                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9235                                         }
9236                                         
9237                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9238                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9239                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
9240                                                 emit_write_barrier (cfg, addr, val);
9241                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9242                                                 GSHAREDVT_FAILURE (*ip);
9243                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9244                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9245
9246                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9247                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9248                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9249                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9250                                         CHECK_TYPELOAD (cmethod->klass);
9251                                         
9252                                         readonly = FALSE;
9253                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9254                                         ins = addr;
9255                                 } else {
9256                                         g_assert_not_reached ();
9257                                 }
9258
9259                                 emit_widen = FALSE;
9260                                 goto call_end;
9261                         }
9262
9263                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9264                         if (ins)
9265                                 goto call_end;
9266
9267                         /* Tail prefix / tail call optimization */
9268
9269                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9270                         /* FIXME: runtime generic context pointer for jumps? */
9271                         /* FIXME: handle this for generic sharing eventually */
9272                         if ((ins_flag & MONO_INST_TAILCALL) &&
9273                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9274                                 supported_tail_call = TRUE;
9275
9276                         if (supported_tail_call) {
9277                                 MonoCallInst *call;
9278
9279                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9280                                 INLINE_FAILURE ("tail call");
9281
9282                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9283
9284                                 if (cfg->backend->have_op_tail_call) {
9285                                         /* Handle tail calls similarly to normal calls */
9286                                         tail_call = TRUE;
9287                                 } else {
9288                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9289
9290                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9291                                         call->tail_call = TRUE;
9292                                         call->method = cmethod;
9293                                         call->signature = mono_method_signature (cmethod);
9294
9295                                         /*
9296                                          * We implement tail calls by storing the actual arguments into the 
9297                                          * argument variables, then emitting a CEE_JMP.
9298                                          */
9299                                         for (i = 0; i < n; ++i) {
9300                                                 /* Prevent argument from being register allocated */
9301                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9302                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9303                                         }
9304                                         ins = (MonoInst*)call;
9305                                         ins->inst_p0 = cmethod;
9306                                         ins->inst_p1 = arg_array [0];
9307                                         MONO_ADD_INS (cfg->cbb, ins);
9308                                         link_bblock (cfg, cfg->cbb, end_bblock);
9309                                         start_new_bblock = 1;
9310
9311                                         // FIXME: Eliminate unreachable epilogs
9312
9313                                         /*
9314                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9315                                          * only reachable from this call.
9316                                          */
9317                                         GET_BBLOCK (cfg, tblock, ip + 5);
9318                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9319                                                 skip_ret = TRUE;
9320                                         push_res = FALSE;
9321
9322                                         goto call_end;
9323                                 }
9324                         }
9325
9326                         /*
9327                          * Virtual calls in llvm-only mode.
9328                          */
9329                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9330                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9331                                 goto call_end;
9332                         }
9333
9334                         /* Common call */
9335                         if (!(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
9336                                 INLINE_FAILURE ("call");
9337                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9338                                                                                           imt_arg, vtable_arg);
9339
9340                         if (tail_call && !cfg->llvm_only) {
9341                                 link_bblock (cfg, cfg->cbb, end_bblock);
9342                                 start_new_bblock = 1;
9343
9344                                 // FIXME: Eliminate unreachable epilogs
9345
9346                                 /*
9347                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9348                                  * only reachable from this call.
9349                                  */
9350                                 GET_BBLOCK (cfg, tblock, ip + 5);
9351                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9352                                         skip_ret = TRUE;
9353                                 push_res = FALSE;
9354                         }
9355
9356                         call_end:
9357
9358                         /* End of call, INS should contain the result of the call, if any */
9359
9360                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9361                                 g_assert (ins);
9362                                 if (emit_widen)
9363                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9364                                 else
9365                                         *sp++ = ins;
9366                         }
9367
9368                         if (keep_this_alive) {
9369                                 MonoInst *dummy_use;
9370
9371                                 /* See mono_emit_method_call_full () */
9372                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9373                         }
9374
9375                         if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
9376                                 /*
9377                                  * Clang can convert these calls to tail calls which screw up the stack
9378                                  * walk. This happens even when the -fno-optimize-sibling-calls
9379                                  * option is passed to clang.
9380                                  * Work around this by emitting a dummy call.
9381                                  */
9382                                 mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
9383                         }
9384
9385                         CHECK_CFG_EXCEPTION;
9386
9387                         ip += 5;
9388                         if (skip_ret) {
9389                                 g_assert (*ip == CEE_RET);
9390                                 ip += 1;
9391                         }
9392                         ins_flag = 0;
9393                         constrained_class = NULL;
9394                         if (need_seq_point)
9395                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9396                         break;
9397                 }
9398                 case CEE_RET:
9399                         if (cfg->method != method) {
9400                                 /* return from inlined method */
9401                                 /* 
9402                                  * If in_count == 0, that means the ret is unreachable due to
9403                                  * being preceeded by a throw. In that case, inline_method () will
9404                                  * handle setting the return value 
9405                                  * (test case: test_0_inline_throw ()).
9406                                  */
9407                                 if (return_var && cfg->cbb->in_count) {
9408                                         MonoType *ret_type = mono_method_signature (method)->ret;
9409
9410                                         MonoInst *store;
9411                                         CHECK_STACK (1);
9412                                         --sp;
9413
9414                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9415                                                 UNVERIFIED;
9416
9417                                         //g_assert (returnvar != -1);
9418                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9419                                         cfg->ret_var_set = TRUE;
9420                                 } 
9421                         } else {
9422                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9423
9424                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9425                                         emit_pop_lmf (cfg);
9426
9427                                 if (cfg->ret) {
9428                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9429
9430                                         if (seq_points && !sym_seq_points) {
9431                                                 /* 
9432                                                  * Place a seq point here too even through the IL stack is not
9433                                                  * empty, so a step over on
9434                                                  * call <FOO>
9435                                                  * ret
9436                                                  * will work correctly.
9437                                                  */
9438                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9439                                                 MONO_ADD_INS (cfg->cbb, ins);
9440                                         }
9441
9442                                         g_assert (!return_var);
9443                                         CHECK_STACK (1);
9444                                         --sp;
9445
9446                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9447                                                 UNVERIFIED;
9448
9449                                         emit_setret (cfg, *sp);
9450                                 }
9451                         }
9452                         if (sp != stack_start)
9453                                 UNVERIFIED;
9454                         MONO_INST_NEW (cfg, ins, OP_BR);
9455                         ip++;
9456                         ins->inst_target_bb = end_bblock;
9457                         MONO_ADD_INS (cfg->cbb, ins);
9458                         link_bblock (cfg, cfg->cbb, end_bblock);
9459                         start_new_bblock = 1;
9460                         break;
9461                 case CEE_BR_S:
9462                         CHECK_OPSIZE (2);
9463                         MONO_INST_NEW (cfg, ins, OP_BR);
9464                         ip++;
9465                         target = ip + 1 + (signed char)(*ip);
9466                         ++ip;
9467                         GET_BBLOCK (cfg, tblock, target);
9468                         link_bblock (cfg, cfg->cbb, tblock);
9469                         ins->inst_target_bb = tblock;
9470                         if (sp != stack_start) {
9471                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9472                                 sp = stack_start;
9473                                 CHECK_UNVERIFIABLE (cfg);
9474                         }
9475                         MONO_ADD_INS (cfg->cbb, ins);
9476                         start_new_bblock = 1;
9477                         inline_costs += BRANCH_COST;
9478                         break;
9479                 case CEE_BEQ_S:
9480                 case CEE_BGE_S:
9481                 case CEE_BGT_S:
9482                 case CEE_BLE_S:
9483                 case CEE_BLT_S:
9484                 case CEE_BNE_UN_S:
9485                 case CEE_BGE_UN_S:
9486                 case CEE_BGT_UN_S:
9487                 case CEE_BLE_UN_S:
9488                 case CEE_BLT_UN_S:
9489                         CHECK_OPSIZE (2);
9490                         CHECK_STACK (2);
9491                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9492                         ip++;
9493                         target = ip + 1 + *(signed char*)ip;
9494                         ip++;
9495
9496                         ADD_BINCOND (NULL);
9497
9498                         sp = stack_start;
9499                         inline_costs += BRANCH_COST;
9500                         break;
9501                 case CEE_BR:
9502                         CHECK_OPSIZE (5);
9503                         MONO_INST_NEW (cfg, ins, OP_BR);
9504                         ip++;
9505
9506                         target = ip + 4 + (gint32)read32(ip);
9507                         ip += 4;
9508                         GET_BBLOCK (cfg, tblock, target);
9509                         link_bblock (cfg, cfg->cbb, tblock);
9510                         ins->inst_target_bb = tblock;
9511                         if (sp != stack_start) {
9512                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9513                                 sp = stack_start;
9514                                 CHECK_UNVERIFIABLE (cfg);
9515                         }
9516
9517                         MONO_ADD_INS (cfg->cbb, ins);
9518
9519                         start_new_bblock = 1;
9520                         inline_costs += BRANCH_COST;
9521                         break;
9522                 case CEE_BRFALSE_S:
9523                 case CEE_BRTRUE_S:
9524                 case CEE_BRFALSE:
9525                 case CEE_BRTRUE: {
9526                         MonoInst *cmp;
9527                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9528                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9529                         guint32 opsize = is_short ? 1 : 4;
9530
9531                         CHECK_OPSIZE (opsize);
9532                         CHECK_STACK (1);
9533                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9534                                 UNVERIFIED;
9535                         ip ++;
9536                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9537                         ip += opsize;
9538
9539                         sp--;
9540
9541                         GET_BBLOCK (cfg, tblock, target);
9542                         link_bblock (cfg, cfg->cbb, tblock);
9543                         GET_BBLOCK (cfg, tblock, ip);
9544                         link_bblock (cfg, cfg->cbb, tblock);
9545
9546                         if (sp != stack_start) {
9547                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9548                                 CHECK_UNVERIFIABLE (cfg);
9549                         }
9550
9551                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9552                         cmp->sreg1 = sp [0]->dreg;
9553                         type_from_op (cfg, cmp, sp [0], NULL);
9554                         CHECK_TYPE (cmp);
9555
9556 #if SIZEOF_REGISTER == 4
9557                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9558                                 /* Convert it to OP_LCOMPARE */
9559                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9560                                 ins->type = STACK_I8;
9561                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9562                                 ins->inst_l = 0;
9563                                 MONO_ADD_INS (cfg->cbb, ins);
9564                                 cmp->opcode = OP_LCOMPARE;
9565                                 cmp->sreg2 = ins->dreg;
9566                         }
9567 #endif
9568                         MONO_ADD_INS (cfg->cbb, cmp);
9569
9570                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9571                         type_from_op (cfg, ins, sp [0], NULL);
9572                         MONO_ADD_INS (cfg->cbb, ins);
9573                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9574                         GET_BBLOCK (cfg, tblock, target);
9575                         ins->inst_true_bb = tblock;
9576                         GET_BBLOCK (cfg, tblock, ip);
9577                         ins->inst_false_bb = tblock;
9578                         start_new_bblock = 2;
9579
9580                         sp = stack_start;
9581                         inline_costs += BRANCH_COST;
9582                         break;
9583                 }
9584                 case CEE_BEQ:
9585                 case CEE_BGE:
9586                 case CEE_BGT:
9587                 case CEE_BLE:
9588                 case CEE_BLT:
9589                 case CEE_BNE_UN:
9590                 case CEE_BGE_UN:
9591                 case CEE_BGT_UN:
9592                 case CEE_BLE_UN:
9593                 case CEE_BLT_UN:
9594                         CHECK_OPSIZE (5);
9595                         CHECK_STACK (2);
9596                         MONO_INST_NEW (cfg, ins, *ip);
9597                         ip++;
9598                         target = ip + 4 + (gint32)read32(ip);
9599                         ip += 4;
9600
9601                         ADD_BINCOND (NULL);
9602
9603                         sp = stack_start;
9604                         inline_costs += BRANCH_COST;
9605                         break;
9606                 case CEE_SWITCH: {
9607                         MonoInst *src1;
9608                         MonoBasicBlock **targets;
9609                         MonoBasicBlock *default_bblock;
9610                         MonoJumpInfoBBTable *table;
9611                         int offset_reg = alloc_preg (cfg);
9612                         int target_reg = alloc_preg (cfg);
9613                         int table_reg = alloc_preg (cfg);
9614                         int sum_reg = alloc_preg (cfg);
9615                         gboolean use_op_switch;
9616
9617                         CHECK_OPSIZE (5);
9618                         CHECK_STACK (1);
9619                         n = read32 (ip + 1);
9620                         --sp;
9621                         src1 = sp [0];
9622                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9623                                 UNVERIFIED;
9624
9625                         ip += 5;
9626                         CHECK_OPSIZE (n * sizeof (guint32));
9627                         target = ip + n * sizeof (guint32);
9628
9629                         GET_BBLOCK (cfg, default_bblock, target);
9630                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9631
9632                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9633                         for (i = 0; i < n; ++i) {
9634                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9635                                 targets [i] = tblock;
9636                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9637                                 ip += 4;
9638                         }
9639
9640                         if (sp != stack_start) {
9641                                 /* 
9642                                  * Link the current bb with the targets as well, so handle_stack_args
9643                                  * will set their in_stack correctly.
9644                                  */
9645                                 link_bblock (cfg, cfg->cbb, default_bblock);
9646                                 for (i = 0; i < n; ++i)
9647                                         link_bblock (cfg, cfg->cbb, targets [i]);
9648
9649                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9650                                 sp = stack_start;
9651                                 CHECK_UNVERIFIABLE (cfg);
9652
9653                                 /* Undo the links */
9654                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9655                                 for (i = 0; i < n; ++i)
9656                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9657                         }
9658
9659                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9660                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9661
9662                         for (i = 0; i < n; ++i)
9663                                 link_bblock (cfg, cfg->cbb, targets [i]);
9664
9665                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9666                         table->table = targets;
9667                         table->table_size = n;
9668
9669                         use_op_switch = FALSE;
9670 #ifdef TARGET_ARM
9671                         /* ARM implements SWITCH statements differently */
9672                         /* FIXME: Make it use the generic implementation */
9673                         if (!cfg->compile_aot)
9674                                 use_op_switch = TRUE;
9675 #endif
9676
9677                         if (COMPILE_LLVM (cfg))
9678                                 use_op_switch = TRUE;
9679
9680                         cfg->cbb->has_jump_table = 1;
9681
9682                         if (use_op_switch) {
9683                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9684                                 ins->sreg1 = src1->dreg;
9685                                 ins->inst_p0 = table;
9686                                 ins->inst_many_bb = targets;
9687                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
9688                                 MONO_ADD_INS (cfg->cbb, ins);
9689                         } else {
9690                                 if (sizeof (gpointer) == 8)
9691                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9692                                 else
9693                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9694
9695 #if SIZEOF_REGISTER == 8
9696                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9697                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9698 #endif
9699
9700                                 if (cfg->compile_aot) {
9701                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9702                                 } else {
9703                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9704                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9705                                         ins->inst_p0 = table;
9706                                         ins->dreg = table_reg;
9707                                         MONO_ADD_INS (cfg->cbb, ins);
9708                                 }
9709
9710                                 /* FIXME: Use load_memindex */
9711                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9712                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9713                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9714                         }
9715                         start_new_bblock = 1;
9716                         inline_costs += (BRANCH_COST * 2);
9717                         break;
9718                 }
9719                 case CEE_LDIND_I1:
9720                 case CEE_LDIND_U1:
9721                 case CEE_LDIND_I2:
9722                 case CEE_LDIND_U2:
9723                 case CEE_LDIND_I4:
9724                 case CEE_LDIND_U4:
9725                 case CEE_LDIND_I8:
9726                 case CEE_LDIND_I:
9727                 case CEE_LDIND_R4:
9728                 case CEE_LDIND_R8:
9729                 case CEE_LDIND_REF:
9730                         CHECK_STACK (1);
9731                         --sp;
9732
9733                         switch (*ip) {
9734                         case CEE_LDIND_R4:
9735                         case CEE_LDIND_R8:
9736                                 dreg = alloc_freg (cfg);
9737                                 break;
9738                         case CEE_LDIND_I8:
9739                                 dreg = alloc_lreg (cfg);
9740                                 break;
9741                         case CEE_LDIND_REF:
9742                                 dreg = alloc_ireg_ref (cfg);
9743                                 break;
9744                         default:
9745                                 dreg = alloc_preg (cfg);
9746                         }
9747
9748                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9749                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9750                         if (*ip == CEE_LDIND_R4)
9751                                 ins->type = cfg->r4_stack_type;
9752                         ins->flags |= ins_flag;
9753                         MONO_ADD_INS (cfg->cbb, ins);
9754                         *sp++ = ins;
9755                         if (ins_flag & MONO_INST_VOLATILE) {
9756                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9757                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9758                         }
9759                         ins_flag = 0;
9760                         ++ip;
9761                         break;
9762                 case CEE_STIND_REF:
9763                 case CEE_STIND_I1:
9764                 case CEE_STIND_I2:
9765                 case CEE_STIND_I4:
9766                 case CEE_STIND_I8:
9767                 case CEE_STIND_R4:
9768                 case CEE_STIND_R8:
9769                 case CEE_STIND_I:
9770                         CHECK_STACK (2);
9771                         sp -= 2;
9772
9773                         if (ins_flag & MONO_INST_VOLATILE) {
9774                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9775                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9776                         }
9777
9778                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9779                         ins->flags |= ins_flag;
9780                         ins_flag = 0;
9781
9782                         MONO_ADD_INS (cfg->cbb, ins);
9783
9784                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
9785                                 emit_write_barrier (cfg, sp [0], sp [1]);
9786
9787                         inline_costs += 1;
9788                         ++ip;
9789                         break;
9790
9791                 case CEE_MUL:
9792                         CHECK_STACK (2);
9793
9794                         MONO_INST_NEW (cfg, ins, (*ip));
9795                         sp -= 2;
9796                         ins->sreg1 = sp [0]->dreg;
9797                         ins->sreg2 = sp [1]->dreg;
9798                         type_from_op (cfg, ins, sp [0], sp [1]);
9799                         CHECK_TYPE (ins);
9800                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9801
9802                         /* Use the immediate opcodes if possible */
9803                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9804                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9805                                 if (imm_opcode != -1) {
9806                                         ins->opcode = imm_opcode;
9807                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9808                                         ins->sreg2 = -1;
9809
9810                                         NULLIFY_INS (sp [1]);
9811                                 }
9812                         }
9813
9814                         MONO_ADD_INS ((cfg)->cbb, (ins));
9815
9816                         *sp++ = mono_decompose_opcode (cfg, ins);
9817                         ip++;
9818                         break;
9819                 case CEE_ADD:
9820                 case CEE_SUB:
9821                 case CEE_DIV:
9822                 case CEE_DIV_UN:
9823                 case CEE_REM:
9824                 case CEE_REM_UN:
9825                 case CEE_AND:
9826                 case CEE_OR:
9827                 case CEE_XOR:
9828                 case CEE_SHL:
9829                 case CEE_SHR:
9830                 case CEE_SHR_UN:
9831                         CHECK_STACK (2);
9832
9833                         MONO_INST_NEW (cfg, ins, (*ip));
9834                         sp -= 2;
9835                         ins->sreg1 = sp [0]->dreg;
9836                         ins->sreg2 = sp [1]->dreg;
9837                         type_from_op (cfg, ins, sp [0], sp [1]);
9838                         CHECK_TYPE (ins);
9839                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9840                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9841
9842                         /* FIXME: Pass opcode to is_inst_imm */
9843
9844                         /* Use the immediate opcodes if possible */
9845                         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)) {
9846                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9847                                 if (imm_opcode != -1) {
9848                                         ins->opcode = imm_opcode;
9849                                         if (sp [1]->opcode == OP_I8CONST) {
9850 #if SIZEOF_REGISTER == 8
9851                                                 ins->inst_imm = sp [1]->inst_l;
9852 #else
9853                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9854                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9855 #endif
9856                                         }
9857                                         else
9858                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9859                                         ins->sreg2 = -1;
9860
9861                                         /* Might be followed by an instruction added by add_widen_op */
9862                                         if (sp [1]->next == NULL)
9863                                                 NULLIFY_INS (sp [1]);
9864                                 }
9865                         }
9866                         MONO_ADD_INS ((cfg)->cbb, (ins));
9867
9868                         *sp++ = mono_decompose_opcode (cfg, ins);
9869                         ip++;
9870                         break;
9871                 case CEE_NEG:
9872                 case CEE_NOT:
9873                 case CEE_CONV_I1:
9874                 case CEE_CONV_I2:
9875                 case CEE_CONV_I4:
9876                 case CEE_CONV_R4:
9877                 case CEE_CONV_R8:
9878                 case CEE_CONV_U4:
9879                 case CEE_CONV_I8:
9880                 case CEE_CONV_U8:
9881                 case CEE_CONV_OVF_I8:
9882                 case CEE_CONV_OVF_U8:
9883                 case CEE_CONV_R_UN:
9884                         CHECK_STACK (1);
9885
9886                         /* Special case this earlier so we have long constants in the IR */
9887                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9888                                 int data = sp [-1]->inst_c0;
9889                                 sp [-1]->opcode = OP_I8CONST;
9890                                 sp [-1]->type = STACK_I8;
9891 #if SIZEOF_REGISTER == 8
9892                                 if ((*ip) == CEE_CONV_U8)
9893                                         sp [-1]->inst_c0 = (guint32)data;
9894                                 else
9895                                         sp [-1]->inst_c0 = data;
9896 #else
9897                                 sp [-1]->inst_ls_word = data;
9898                                 if ((*ip) == CEE_CONV_U8)
9899                                         sp [-1]->inst_ms_word = 0;
9900                                 else
9901                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9902 #endif
9903                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9904                         }
9905                         else {
9906                                 ADD_UNOP (*ip);
9907                         }
9908                         ip++;
9909                         break;
9910                 case CEE_CONV_OVF_I4:
9911                 case CEE_CONV_OVF_I1:
9912                 case CEE_CONV_OVF_I2:
9913                 case CEE_CONV_OVF_I:
9914                 case CEE_CONV_OVF_U:
9915                         CHECK_STACK (1);
9916
9917                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9918                                 ADD_UNOP (CEE_CONV_OVF_I8);
9919                                 ADD_UNOP (*ip);
9920                         } else {
9921                                 ADD_UNOP (*ip);
9922                         }
9923                         ip++;
9924                         break;
9925                 case CEE_CONV_OVF_U1:
9926                 case CEE_CONV_OVF_U2:
9927                 case CEE_CONV_OVF_U4:
9928                         CHECK_STACK (1);
9929
9930                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9931                                 ADD_UNOP (CEE_CONV_OVF_U8);
9932                                 ADD_UNOP (*ip);
9933                         } else {
9934                                 ADD_UNOP (*ip);
9935                         }
9936                         ip++;
9937                         break;
9938                 case CEE_CONV_OVF_I1_UN:
9939                 case CEE_CONV_OVF_I2_UN:
9940                 case CEE_CONV_OVF_I4_UN:
9941                 case CEE_CONV_OVF_I8_UN:
9942                 case CEE_CONV_OVF_U1_UN:
9943                 case CEE_CONV_OVF_U2_UN:
9944                 case CEE_CONV_OVF_U4_UN:
9945                 case CEE_CONV_OVF_U8_UN:
9946                 case CEE_CONV_OVF_I_UN:
9947                 case CEE_CONV_OVF_U_UN:
9948                 case CEE_CONV_U2:
9949                 case CEE_CONV_U1:
9950                 case CEE_CONV_I:
9951                 case CEE_CONV_U:
9952                         CHECK_STACK (1);
9953                         ADD_UNOP (*ip);
9954                         CHECK_CFG_EXCEPTION;
9955                         ip++;
9956                         break;
9957                 case CEE_ADD_OVF:
9958                 case CEE_ADD_OVF_UN:
9959                 case CEE_MUL_OVF:
9960                 case CEE_MUL_OVF_UN:
9961                 case CEE_SUB_OVF:
9962                 case CEE_SUB_OVF_UN:
9963                         CHECK_STACK (2);
9964                         ADD_BINOP (*ip);
9965                         ip++;
9966                         break;
9967                 case CEE_CPOBJ:
9968                         GSHAREDVT_FAILURE (*ip);
9969                         CHECK_OPSIZE (5);
9970                         CHECK_STACK (2);
9971                         token = read32 (ip + 1);
9972                         klass = mini_get_class (method, token, generic_context);
9973                         CHECK_TYPELOAD (klass);
9974                         sp -= 2;
9975                         if (generic_class_is_reference_type (cfg, klass)) {
9976                                 MonoInst *store, *load;
9977                                 int dreg = alloc_ireg_ref (cfg);
9978
9979                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9980                                 load->flags |= ins_flag;
9981                                 MONO_ADD_INS (cfg->cbb, load);
9982
9983                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9984                                 store->flags |= ins_flag;
9985                                 MONO_ADD_INS (cfg->cbb, store);
9986
9987                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9988                                         emit_write_barrier (cfg, sp [0], sp [1]);
9989                         } else {
9990                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9991                         }
9992                         ins_flag = 0;
9993                         ip += 5;
9994                         break;
9995                 case CEE_LDOBJ: {
9996                         int loc_index = -1;
9997                         int stloc_len = 0;
9998
9999                         CHECK_OPSIZE (5);
10000                         CHECK_STACK (1);
10001                         --sp;
10002                         token = read32 (ip + 1);
10003                         klass = mini_get_class (method, token, generic_context);
10004                         CHECK_TYPELOAD (klass);
10005
10006                         /* Optimize the common ldobj+stloc combination */
10007                         switch (ip [5]) {
10008                         case CEE_STLOC_S:
10009                                 loc_index = ip [6];
10010                                 stloc_len = 2;
10011                                 break;
10012                         case CEE_STLOC_0:
10013                         case CEE_STLOC_1:
10014                         case CEE_STLOC_2:
10015                         case CEE_STLOC_3:
10016                                 loc_index = ip [5] - CEE_STLOC_0;
10017                                 stloc_len = 1;
10018                                 break;
10019                         default:
10020                                 break;
10021                         }
10022
10023                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10024                                 CHECK_LOCAL (loc_index);
10025
10026                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10027                                 ins->dreg = cfg->locals [loc_index]->dreg;
10028                                 ins->flags |= ins_flag;
10029                                 ip += 5;
10030                                 ip += stloc_len;
10031                                 if (ins_flag & MONO_INST_VOLATILE) {
10032                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10033                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10034                                 }
10035                                 ins_flag = 0;
10036                                 break;
10037                         }
10038
10039                         /* Optimize the ldobj+stobj combination */
10040                         /* The reference case ends up being a load+store anyway */
10041                         /* Skip this if the operation is volatile. */
10042                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) {
10043                                 CHECK_STACK (1);
10044
10045                                 sp --;
10046
10047                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10048
10049                                 ip += 5 + 5;
10050                                 ins_flag = 0;
10051                                 break;
10052                         }
10053
10054                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10055                         ins->flags |= ins_flag;
10056                         *sp++ = ins;
10057
10058                         if (ins_flag & MONO_INST_VOLATILE) {
10059                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10060                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10061                         }
10062
10063                         ip += 5;
10064                         ins_flag = 0;
10065                         inline_costs += 1;
10066                         break;
10067                 }
10068                 case CEE_LDSTR:
10069                         CHECK_STACK_OVF (1);
10070                         CHECK_OPSIZE (5);
10071                         n = read32 (ip + 1);
10072
10073                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10074                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10075                                 ins->type = STACK_OBJ;
10076                                 *sp = ins;
10077                         }
10078                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10079                                 MonoInst *iargs [1];
10080                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10081
10082                                 if (cfg->compile_aot)
10083                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10084                                 else
10085                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10086                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10087                         } else {
10088                                 if (cfg->opt & MONO_OPT_SHARED) {
10089                                         MonoInst *iargs [3];
10090
10091                                         if (cfg->compile_aot) {
10092                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10093                                         }
10094                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10095                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10096                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10097                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10098                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10099                                         CHECK_CFG_ERROR;
10100                                 } else {
10101                                         if (cfg->cbb->out_of_line) {
10102                                                 MonoInst *iargs [2];
10103
10104                                                 if (image == mono_defaults.corlib) {
10105                                                         /* 
10106                                                          * Avoid relocations in AOT and save some space by using a 
10107                                                          * version of helper_ldstr specialized to mscorlib.
10108                                                          */
10109                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10110                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10111                                                 } else {
10112                                                         /* Avoid creating the string object */
10113                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10114                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10115                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10116                                                 }
10117                                         } 
10118                                         else
10119                                         if (cfg->compile_aot) {
10120                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10121                                                 *sp = ins;
10122                                                 MONO_ADD_INS (cfg->cbb, ins);
10123                                         } 
10124                                         else {
10125                                                 NEW_PCONST (cfg, ins, NULL);
10126                                                 ins->type = STACK_OBJ;
10127                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10128                                                 CHECK_CFG_ERROR;
10129                                                 
10130                                                 if (!ins->inst_p0)
10131                                                         OUT_OF_MEMORY_FAILURE;
10132
10133                                                 *sp = ins;
10134                                                 MONO_ADD_INS (cfg->cbb, ins);
10135                                         }
10136                                 }
10137                         }
10138
10139                         sp++;
10140                         ip += 5;
10141                         break;
10142                 case CEE_NEWOBJ: {
10143                         MonoInst *iargs [2];
10144                         MonoMethodSignature *fsig;
10145                         MonoInst this_ins;
10146                         MonoInst *alloc;
10147                         MonoInst *vtable_arg = NULL;
10148
10149                         CHECK_OPSIZE (5);
10150                         token = read32 (ip + 1);
10151                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10152                         CHECK_CFG_ERROR;
10153
10154                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10155                         CHECK_CFG_ERROR;
10156
10157                         mono_save_token_info (cfg, image, token, cmethod);
10158
10159                         if (!mono_class_init (cmethod->klass))
10160                                 TYPE_LOAD_ERROR (cmethod->klass);
10161
10162                         context_used = mini_method_check_context_used (cfg, cmethod);
10163
10164                         if (mono_security_core_clr_enabled ())
10165                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10166
10167                         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)) {
10168                                 emit_class_init (cfg, cmethod->klass);
10169                                 CHECK_TYPELOAD (cmethod->klass);
10170                         }
10171
10172                         /*
10173                         if (cfg->gsharedvt) {
10174                                 if (mini_is_gsharedvt_variable_signature (sig))
10175                                         GSHAREDVT_FAILURE (*ip);
10176                         }
10177                         */
10178
10179                         n = fsig->param_count;
10180                         CHECK_STACK (n);
10181
10182                         /* 
10183                          * Generate smaller code for the common newobj <exception> instruction in
10184                          * argument checking code.
10185                          */
10186                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10187                                 is_exception_class (cmethod->klass) && n <= 2 &&
10188                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10189                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10190                                 MonoInst *iargs [3];
10191
10192                                 sp -= n;
10193
10194                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10195                                 switch (n) {
10196                                 case 0:
10197                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10198                                         break;
10199                                 case 1:
10200                                         iargs [1] = sp [0];
10201                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10202                                         break;
10203                                 case 2:
10204                                         iargs [1] = sp [0];
10205                                         iargs [2] = sp [1];
10206                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10207                                         break;
10208                                 default:
10209                                         g_assert_not_reached ();
10210                                 }
10211
10212                                 ip += 5;
10213                                 inline_costs += 5;
10214                                 break;
10215                         }
10216
10217                         /* move the args to allow room for 'this' in the first position */
10218                         while (n--) {
10219                                 --sp;
10220                                 sp [1] = sp [0];
10221                         }
10222
10223                         /* check_call_signature () requires sp[0] to be set */
10224                         this_ins.type = STACK_OBJ;
10225                         sp [0] = &this_ins;
10226                         if (check_call_signature (cfg, fsig, sp))
10227                                 UNVERIFIED;
10228
10229                         iargs [0] = NULL;
10230
10231                         if (mini_class_is_system_array (cmethod->klass)) {
10232                                 *sp = emit_get_rgctx_method (cfg, context_used,
10233                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10234
10235                                 /* Avoid varargs in the common case */
10236                                 if (fsig->param_count == 1)
10237                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10238                                 else if (fsig->param_count == 2)
10239                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10240                                 else if (fsig->param_count == 3)
10241                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10242                                 else if (fsig->param_count == 4)
10243                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10244                                 else
10245                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10246                         } else if (cmethod->string_ctor) {
10247                                 g_assert (!context_used);
10248                                 g_assert (!vtable_arg);
10249                                 /* we simply pass a null pointer */
10250                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10251                                 /* now call the string ctor */
10252                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10253                         } else {
10254                                 if (cmethod->klass->valuetype) {
10255                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10256                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10257                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10258
10259                                         alloc = NULL;
10260
10261                                         /* 
10262                                          * The code generated by mini_emit_virtual_call () expects
10263                                          * iargs [0] to be a boxed instance, but luckily the vcall
10264                                          * will be transformed into a normal call there.
10265                                          */
10266                                 } else if (context_used) {
10267                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10268                                         *sp = alloc;
10269                                 } else {
10270                                         MonoVTable *vtable = NULL;
10271
10272                                         if (!cfg->compile_aot)
10273                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10274                                         CHECK_TYPELOAD (cmethod->klass);
10275
10276                                         /*
10277                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10278                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10279                                          * As a workaround, we call class cctors before allocating objects.
10280                                          */
10281                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10282                                                 emit_class_init (cfg, cmethod->klass);
10283                                                 if (cfg->verbose_level > 2)
10284                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10285                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10286                                         }
10287
10288                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10289                                         *sp = alloc;
10290                                 }
10291                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10292
10293                                 if (alloc)
10294                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10295
10296                                 /* Now call the actual ctor */
10297                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10298                                 CHECK_CFG_EXCEPTION;
10299                         }
10300
10301                         if (alloc == NULL) {
10302                                 /* Valuetype */
10303                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10304                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10305                                 *sp++= ins;
10306                         } else {
10307                                 *sp++ = alloc;
10308                         }
10309                         
10310                         ip += 5;
10311                         inline_costs += 5;
10312                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10313                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10314                         break;
10315                 }
10316                 case CEE_CASTCLASS:
10317                 case CEE_ISINST: {
10318                         CHECK_STACK (1);
10319                         --sp;
10320                         CHECK_OPSIZE (5);
10321                         token = read32 (ip + 1);
10322                         klass = mini_get_class (method, token, generic_context);
10323                         CHECK_TYPELOAD (klass);
10324                         if (sp [0]->type != STACK_OBJ)
10325                                 UNVERIFIED;
10326
10327                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
10328                         ins->dreg = alloc_preg (cfg);
10329                         ins->sreg1 = (*sp)->dreg;
10330                         ins->klass = klass;
10331                         ins->type = STACK_OBJ;
10332                         MONO_ADD_INS (cfg->cbb, ins);
10333
10334                         CHECK_CFG_EXCEPTION;
10335                         *sp++ = ins;
10336                         ip += 5;
10337
10338                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10339                         break;
10340                 }
10341                 case CEE_UNBOX_ANY: {
10342                         MonoInst *res, *addr;
10343
10344                         CHECK_STACK (1);
10345                         --sp;
10346                         CHECK_OPSIZE (5);
10347                         token = read32 (ip + 1);
10348                         klass = mini_get_class (method, token, generic_context);
10349                         CHECK_TYPELOAD (klass);
10350
10351                         mono_save_token_info (cfg, image, token, klass);
10352
10353                         context_used = mini_class_check_context_used (cfg, klass);
10354
10355                         if (mini_is_gsharedvt_klass (klass)) {
10356                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10357                                 inline_costs += 2;
10358                         } else if (generic_class_is_reference_type (cfg, klass)) {
10359                                 if (MONO_INS_IS_PCONST_NULL (*sp)) {
10360                                         EMIT_NEW_PCONST (cfg, res, NULL);
10361                                         res->type = STACK_OBJ;
10362                                 } else {
10363                                         MONO_INST_NEW (cfg, res, OP_CASTCLASS);
10364                                         res->dreg = alloc_preg (cfg);
10365                                         res->sreg1 = (*sp)->dreg;
10366                                         res->klass = klass;
10367                                         res->type = STACK_OBJ;
10368                                         MONO_ADD_INS (cfg->cbb, res);
10369                                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10370                                 }
10371                         } else if (mono_class_is_nullable (klass)) {
10372                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10373                         } else {
10374                                 addr = handle_unbox (cfg, klass, sp, context_used);
10375                                 /* LDOBJ */
10376                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10377                                 res = ins;
10378                                 inline_costs += 2;
10379                         }
10380
10381                         *sp ++ = res;
10382                         ip += 5;
10383                         break;
10384                 }
10385                 case CEE_BOX: {
10386                         MonoInst *val;
10387                         MonoClass *enum_class;
10388                         MonoMethod *has_flag;
10389
10390                         CHECK_STACK (1);
10391                         --sp;
10392                         val = *sp;
10393                         CHECK_OPSIZE (5);
10394                         token = read32 (ip + 1);
10395                         klass = mini_get_class (method, token, generic_context);
10396                         CHECK_TYPELOAD (klass);
10397
10398                         mono_save_token_info (cfg, image, token, klass);
10399
10400                         context_used = mini_class_check_context_used (cfg, klass);
10401
10402                         if (generic_class_is_reference_type (cfg, klass)) {
10403                                 *sp++ = val;
10404                                 ip += 5;
10405                                 break;
10406                         }
10407
10408                         if (klass == mono_defaults.void_class)
10409                                 UNVERIFIED;
10410                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10411                                 UNVERIFIED;
10412                         /* frequent check in generic code: box (struct), brtrue */
10413
10414                         /*
10415                          * Look for:
10416                          *
10417                          *   <push int/long ptr>
10418                          *   <push int/long>
10419                          *   box MyFlags
10420                          *   constrained. MyFlags
10421                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10422                          *
10423                          * If we find this sequence and the operand types on box and constrained
10424                          * are equal, we can emit a specialized instruction sequence instead of
10425                          * the very slow HasFlag () call.
10426                          */
10427                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10428                             /* Cheap checks first. */
10429                             ip + 5 + 6 + 5 < end &&
10430                             ip [5] == CEE_PREFIX1 &&
10431                             ip [6] == CEE_CONSTRAINED_ &&
10432                             ip [11] == CEE_CALLVIRT &&
10433                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10434                             mono_class_is_enum (klass) &&
10435                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10436                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10437                             has_flag->klass == mono_defaults.enum_class &&
10438                             !strcmp (has_flag->name, "HasFlag") &&
10439                             has_flag->signature->hasthis &&
10440                             has_flag->signature->param_count == 1) {
10441                                 CHECK_TYPELOAD (enum_class);
10442
10443                                 if (enum_class == klass) {
10444                                         MonoInst *enum_this, *enum_flag;
10445
10446                                         ip += 5 + 6 + 5;
10447                                         --sp;
10448
10449                                         enum_this = sp [0];
10450                                         enum_flag = sp [1];
10451
10452                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10453                                         break;
10454                                 }
10455                         }
10456
10457                         // FIXME: LLVM can't handle the inconsistent bb linking
10458                         if (!mono_class_is_nullable (klass) &&
10459                                 !mini_is_gsharedvt_klass (klass) &&
10460                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10461                                 (ip [5] == CEE_BRTRUE || 
10462                                  ip [5] == CEE_BRTRUE_S ||
10463                                  ip [5] == CEE_BRFALSE ||
10464                                  ip [5] == CEE_BRFALSE_S)) {
10465                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10466                                 int dreg;
10467                                 MonoBasicBlock *true_bb, *false_bb;
10468
10469                                 ip += 5;
10470
10471                                 if (cfg->verbose_level > 3) {
10472                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10473                                         printf ("<box+brtrue opt>\n");
10474                                 }
10475
10476                                 switch (*ip) {
10477                                 case CEE_BRTRUE_S:
10478                                 case CEE_BRFALSE_S:
10479                                         CHECK_OPSIZE (2);
10480                                         ip++;
10481                                         target = ip + 1 + (signed char)(*ip);
10482                                         ip++;
10483                                         break;
10484                                 case CEE_BRTRUE:
10485                                 case CEE_BRFALSE:
10486                                         CHECK_OPSIZE (5);
10487                                         ip++;
10488                                         target = ip + 4 + (gint)(read32 (ip));
10489                                         ip += 4;
10490                                         break;
10491                                 default:
10492                                         g_assert_not_reached ();
10493                                 }
10494
10495                                 /* 
10496                                  * We need to link both bblocks, since it is needed for handling stack
10497                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10498                                  * Branching to only one of them would lead to inconsistencies, so
10499                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10500                                  */
10501                                 GET_BBLOCK (cfg, true_bb, target);
10502                                 GET_BBLOCK (cfg, false_bb, ip);
10503
10504                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10505                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10506
10507                                 if (sp != stack_start) {
10508                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10509                                         sp = stack_start;
10510                                         CHECK_UNVERIFIABLE (cfg);
10511                                 }
10512
10513                                 if (COMPILE_LLVM (cfg)) {
10514                                         dreg = alloc_ireg (cfg);
10515                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10516                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10517
10518                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10519                                 } else {
10520                                         /* The JIT can't eliminate the iconst+compare */
10521                                         MONO_INST_NEW (cfg, ins, OP_BR);
10522                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10523                                         MONO_ADD_INS (cfg->cbb, ins);
10524                                 }
10525
10526                                 start_new_bblock = 1;
10527                                 break;
10528                         }
10529
10530                         *sp++ = handle_box (cfg, val, klass, context_used);
10531
10532                         CHECK_CFG_EXCEPTION;
10533                         ip += 5;
10534                         inline_costs += 1;
10535                         break;
10536                 }
10537                 case CEE_UNBOX: {
10538                         CHECK_STACK (1);
10539                         --sp;
10540                         CHECK_OPSIZE (5);
10541                         token = read32 (ip + 1);
10542                         klass = mini_get_class (method, token, generic_context);
10543                         CHECK_TYPELOAD (klass);
10544
10545                         mono_save_token_info (cfg, image, token, klass);
10546
10547                         context_used = mini_class_check_context_used (cfg, klass);
10548
10549                         if (mono_class_is_nullable (klass)) {
10550                                 MonoInst *val;
10551
10552                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10553                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10554
10555                                 *sp++= ins;
10556                         } else {
10557                                 ins = handle_unbox (cfg, klass, sp, context_used);
10558                                 *sp++ = ins;
10559                         }
10560                         ip += 5;
10561                         inline_costs += 2;
10562                         break;
10563                 }
10564                 case CEE_LDFLD:
10565                 case CEE_LDFLDA:
10566                 case CEE_STFLD:
10567                 case CEE_LDSFLD:
10568                 case CEE_LDSFLDA:
10569                 case CEE_STSFLD: {
10570                         MonoClassField *field;
10571 #ifndef DISABLE_REMOTING
10572                         int costs;
10573 #endif
10574                         guint foffset;
10575                         gboolean is_instance;
10576                         int op;
10577                         gpointer addr = NULL;
10578                         gboolean is_special_static;
10579                         MonoType *ftype;
10580                         MonoInst *store_val = NULL;
10581                         MonoInst *thread_ins;
10582
10583                         op = *ip;
10584                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10585                         if (is_instance) {
10586                                 if (op == CEE_STFLD) {
10587                                         CHECK_STACK (2);
10588                                         sp -= 2;
10589                                         store_val = sp [1];
10590                                 } else {
10591                                         CHECK_STACK (1);
10592                                         --sp;
10593                                 }
10594                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10595                                         UNVERIFIED;
10596                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10597                                         UNVERIFIED;
10598                         } else {
10599                                 if (op == CEE_STSFLD) {
10600                                         CHECK_STACK (1);
10601                                         sp--;
10602                                         store_val = sp [0];
10603                                 }
10604                         }
10605
10606                         CHECK_OPSIZE (5);
10607                         token = read32 (ip + 1);
10608                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10609                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
10610                                 klass = field->parent;
10611                         }
10612                         else {
10613                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10614                                 CHECK_CFG_ERROR;
10615                         }
10616                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10617                                 FIELD_ACCESS_FAILURE (method, field);
10618                         mono_class_init (klass);
10619
10620                         /* if the class is Critical then transparent code cannot access it's fields */
10621                         if (!is_instance && mono_security_core_clr_enabled ())
10622                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10623
10624                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10625                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10626                         if (mono_security_core_clr_enabled ())
10627                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10628                         */
10629
10630                         ftype = mono_field_get_type (field);
10631
10632                         /*
10633                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10634                          * the static case.
10635                          */
10636                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
10637                                 switch (op) {
10638                                 case CEE_LDFLD:
10639                                         op = CEE_LDSFLD;
10640                                         break;
10641                                 case CEE_STFLD:
10642                                         op = CEE_STSFLD;
10643                                         break;
10644                                 case CEE_LDFLDA:
10645                                         op = CEE_LDSFLDA;
10646                                         break;
10647                                 default:
10648                                         g_assert_not_reached ();
10649                                 }
10650                                 is_instance = FALSE;
10651                         }
10652
10653                         context_used = mini_class_check_context_used (cfg, klass);
10654
10655                         /* INSTANCE CASE */
10656
10657                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10658                         if (op == CEE_STFLD) {
10659                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10660                                         UNVERIFIED;
10661 #ifndef DISABLE_REMOTING
10662                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10663                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10664                                         MonoInst *iargs [5];
10665
10666                                         GSHAREDVT_FAILURE (op);
10667
10668                                         iargs [0] = sp [0];
10669                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10670                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10671                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10672                                                     field->offset);
10673                                         iargs [4] = sp [1];
10674
10675                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10676                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10677                                                                                            iargs, ip, cfg->real_offset, TRUE);
10678                                                 CHECK_CFG_EXCEPTION;
10679                                                 g_assert (costs > 0);
10680                                                       
10681                                                 cfg->real_offset += 5;
10682
10683                                                 inline_costs += costs;
10684                                         } else {
10685                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10686                                         }
10687                                 } else
10688 #endif
10689                                 {
10690                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
10691
10692                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10693
10694                                         if (ins_flag & MONO_INST_VOLATILE) {
10695                                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10696                                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10697                                         }
10698
10699                                         if (mini_is_gsharedvt_klass (klass)) {
10700                                                 MonoInst *offset_ins;
10701
10702                                                 context_used = mini_class_check_context_used (cfg, klass);
10703
10704                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10705                                                 /* The value is offset by 1 */
10706                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10707                                                 dreg = alloc_ireg_mp (cfg);
10708                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10709                                                 wbarrier_ptr_ins = ins;
10710                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10711                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10712                                         } else {
10713                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10714                                         }
10715                                         if (sp [0]->opcode != OP_LDADDR)
10716                                                 store->flags |= MONO_INST_FAULT;
10717
10718                                         if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
10719                                                 if (mini_is_gsharedvt_klass (klass)) {
10720                                                         g_assert (wbarrier_ptr_ins);
10721                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
10722                                                 } else {
10723                                                         /* insert call to write barrier */
10724                                                         MonoInst *ptr;
10725                                                         int dreg;
10726
10727                                                         dreg = alloc_ireg_mp (cfg);
10728                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10729                                                         emit_write_barrier (cfg, ptr, sp [1]);
10730                                                 }
10731                                         }
10732
10733                                         store->flags |= ins_flag;
10734                                 }
10735                                 ins_flag = 0;
10736                                 ip += 5;
10737                                 break;
10738                         }
10739
10740 #ifndef DISABLE_REMOTING
10741                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10742                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10743                                 MonoInst *iargs [4];
10744
10745                                 GSHAREDVT_FAILURE (op);
10746
10747                                 iargs [0] = sp [0];
10748                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10749                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10750                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10751                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10752                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10753                                                                                    iargs, ip, cfg->real_offset, TRUE);
10754                                         CHECK_CFG_EXCEPTION;
10755                                         g_assert (costs > 0);
10756                                                       
10757                                         cfg->real_offset += 5;
10758
10759                                         *sp++ = iargs [0];
10760
10761                                         inline_costs += costs;
10762                                 } else {
10763                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10764                                         *sp++ = ins;
10765                                 }
10766                         } else 
10767 #endif
10768                         if (is_instance) {
10769                                 if (sp [0]->type == STACK_VTYPE) {
10770                                         MonoInst *var;
10771
10772                                         /* Have to compute the address of the variable */
10773
10774                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10775                                         if (!var)
10776                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10777                                         else
10778                                                 g_assert (var->klass == klass);
10779                                         
10780                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10781                                         sp [0] = ins;
10782                                 }
10783
10784                                 if (op == CEE_LDFLDA) {
10785                                         if (sp [0]->type == STACK_OBJ) {
10786                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10787                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10788                                         }
10789
10790                                         dreg = alloc_ireg_mp (cfg);
10791
10792                                         if (mini_is_gsharedvt_klass (klass)) {
10793                                                 MonoInst *offset_ins;
10794
10795                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10796                                                 /* The value is offset by 1 */
10797                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10798                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10799                                         } else {
10800                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10801                                         }
10802                                         ins->klass = mono_class_from_mono_type (field->type);
10803                                         ins->type = STACK_MP;
10804                                         *sp++ = ins;
10805                                 } else {
10806                                         MonoInst *load;
10807
10808                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10809
10810                                         if (sp [0]->opcode == OP_LDADDR && klass->simd_type && cfg->opt & MONO_OPT_SIMD) {
10811                                                 ins = mono_emit_simd_field_load (cfg, field, sp [0]);
10812                                                 if (ins) {
10813                                                         *sp++ = ins;
10814                                                         ins_flag = 0;
10815                                                         ip += 5;
10816                                                         break;
10817                                                 }
10818                                         }
10819
10820                                         if (mini_is_gsharedvt_klass (klass)) {
10821                                                 MonoInst *offset_ins;
10822
10823                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10824                                                 /* The value is offset by 1 */
10825                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10826                                                 dreg = alloc_ireg_mp (cfg);
10827                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10828                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10829                                         } else {
10830                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10831                                         }
10832                                         load->flags |= ins_flag;
10833                                         if (sp [0]->opcode != OP_LDADDR)
10834                                                 load->flags |= MONO_INST_FAULT;
10835                                         *sp++ = load;
10836                                 }
10837                         }
10838
10839                         if (is_instance) {
10840                                 ins_flag = 0;
10841                                 ip += 5;
10842                                 break;
10843                         }
10844
10845                         /* STATIC CASE */
10846                         context_used = mini_class_check_context_used (cfg, klass);
10847
10848                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
10849                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
10850                                 CHECK_CFG_ERROR;
10851                         }
10852
10853                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10854                          * to be called here.
10855                          */
10856                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10857                                 mono_class_vtable (cfg->domain, klass);
10858                                 CHECK_TYPELOAD (klass);
10859                         }
10860                         mono_domain_lock (cfg->domain);
10861                         if (cfg->domain->special_static_fields)
10862                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10863                         mono_domain_unlock (cfg->domain);
10864
10865                         is_special_static = mono_class_field_is_special_static (field);
10866
10867                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10868                                 thread_ins = mono_create_tls_get (cfg, TLS_KEY_THREAD);
10869                         else
10870                                 thread_ins = NULL;
10871
10872                         /* Generate IR to compute the field address */
10873                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10874                                 /*
10875                                  * Fast access to TLS data
10876                                  * Inline version of get_thread_static_data () in
10877                                  * threads.c.
10878                                  */
10879                                 guint32 offset;
10880                                 int idx, static_data_reg, array_reg, dreg;
10881
10882                                 if (context_used && cfg->gsharedvt && mini_is_gsharedvt_klass (klass))
10883                                         GSHAREDVT_FAILURE (op);
10884
10885                                 static_data_reg = alloc_ireg (cfg);
10886                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
10887
10888                                 if (cfg->compile_aot) {
10889                                         int offset_reg, offset2_reg, idx_reg;
10890
10891                                         /* For TLS variables, this will return the TLS offset */
10892                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10893                                         offset_reg = ins->dreg;
10894                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10895                                         idx_reg = alloc_ireg (cfg);
10896                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
10897                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10898                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10899                                         array_reg = alloc_ireg (cfg);
10900                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10901                                         offset2_reg = alloc_ireg (cfg);
10902                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
10903                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
10904                                         dreg = alloc_ireg (cfg);
10905                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10906                                 } else {
10907                                         offset = (gsize)addr & 0x7fffffff;
10908                                         idx = offset & 0x3f;
10909
10910                                         array_reg = alloc_ireg (cfg);
10911                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10912                                         dreg = alloc_ireg (cfg);
10913                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
10914                                 }
10915                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10916                                         (cfg->compile_aot && is_special_static) ||
10917                                         (context_used && is_special_static)) {
10918                                 MonoInst *iargs [2];
10919
10920                                 g_assert (field->parent);
10921                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10922                                 if (context_used) {
10923                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10924                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10925                                 } else {
10926                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10927                                 }
10928                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10929                         } else if (context_used) {
10930                                 MonoInst *static_data;
10931
10932                                 /*
10933                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10934                                         method->klass->name_space, method->klass->name, method->name,
10935                                         depth, field->offset);
10936                                 */
10937
10938                                 if (mono_class_needs_cctor_run (klass, method))
10939                                         emit_class_init (cfg, klass);
10940
10941                                 /*
10942                                  * The pointer we're computing here is
10943                                  *
10944                                  *   super_info.static_data + field->offset
10945                                  */
10946                                 static_data = mini_emit_get_rgctx_klass (cfg, context_used,
10947                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10948
10949                                 if (mini_is_gsharedvt_klass (klass)) {
10950                                         MonoInst *offset_ins;
10951
10952                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10953                                         /* The value is offset by 1 */
10954                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10955                                         dreg = alloc_ireg_mp (cfg);
10956                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10957                                 } else if (field->offset == 0) {
10958                                         ins = static_data;
10959                                 } else {
10960                                         int addr_reg = mono_alloc_preg (cfg);
10961                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10962                                 }
10963                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10964                                 MonoInst *iargs [2];
10965
10966                                 g_assert (field->parent);
10967                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10968                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10969                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10970                         } else {
10971                                 MonoVTable *vtable = NULL;
10972
10973                                 if (!cfg->compile_aot)
10974                                         vtable = mono_class_vtable (cfg->domain, klass);
10975                                 CHECK_TYPELOAD (klass);
10976
10977                                 if (!addr) {
10978                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10979                                                 if (!(g_slist_find (class_inits, klass))) {
10980                                                         emit_class_init (cfg, klass);
10981                                                         if (cfg->verbose_level > 2)
10982                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10983                                                         class_inits = g_slist_prepend (class_inits, klass);
10984                                                 }
10985                                         } else {
10986                                                 if (cfg->run_cctors) {
10987                                                         /* This makes so that inline cannot trigger */
10988                                                         /* .cctors: too many apps depend on them */
10989                                                         /* running with a specific order... */
10990                                                         g_assert (vtable);
10991                                                         if (! vtable->initialized)
10992                                                                 INLINE_FAILURE ("class init");
10993                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
10994                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
10995                                                                 goto exception_exit;
10996                                                         }
10997                                                 }
10998                                         }
10999                                         if (cfg->compile_aot)
11000                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11001                                         else {
11002                                                 g_assert (vtable);
11003                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11004                                                 g_assert (addr);
11005                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11006                                         }
11007                                 } else {
11008                                         MonoInst *iargs [1];
11009                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11010                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11011                                 }
11012                         }
11013
11014                         /* Generate IR to do the actual load/store operation */
11015
11016                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11017                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11018                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11019                         }
11020
11021                         if (op == CEE_LDSFLDA) {
11022                                 ins->klass = mono_class_from_mono_type (ftype);
11023                                 ins->type = STACK_PTR;
11024                                 *sp++ = ins;
11025                         } else if (op == CEE_STSFLD) {
11026                                 MonoInst *store;
11027
11028                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11029                                 store->flags |= ins_flag;
11030                         } else {
11031                                 gboolean is_const = FALSE;
11032                                 MonoVTable *vtable = NULL;
11033                                 gpointer addr = NULL;
11034
11035                                 if (!context_used) {
11036                                         vtable = mono_class_vtable (cfg->domain, klass);
11037                                         CHECK_TYPELOAD (klass);
11038                                 }
11039                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11040                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11041                                         int ro_type = ftype->type;
11042                                         if (!addr)
11043                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11044                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11045                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11046                                         }
11047
11048                                         GSHAREDVT_FAILURE (op);
11049
11050                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11051                                         is_const = TRUE;
11052                                         switch (ro_type) {
11053                                         case MONO_TYPE_BOOLEAN:
11054                                         case MONO_TYPE_U1:
11055                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11056                                                 sp++;
11057                                                 break;
11058                                         case MONO_TYPE_I1:
11059                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11060                                                 sp++;
11061                                                 break;                                          
11062                                         case MONO_TYPE_CHAR:
11063                                         case MONO_TYPE_U2:
11064                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11065                                                 sp++;
11066                                                 break;
11067                                         case MONO_TYPE_I2:
11068                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11069                                                 sp++;
11070                                                 break;
11071                                                 break;
11072                                         case MONO_TYPE_I4:
11073                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11074                                                 sp++;
11075                                                 break;                                          
11076                                         case MONO_TYPE_U4:
11077                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11078                                                 sp++;
11079                                                 break;
11080                                         case MONO_TYPE_I:
11081                                         case MONO_TYPE_U:
11082                                         case MONO_TYPE_PTR:
11083                                         case MONO_TYPE_FNPTR:
11084                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11085                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11086                                                 sp++;
11087                                                 break;
11088                                         case MONO_TYPE_STRING:
11089                                         case MONO_TYPE_OBJECT:
11090                                         case MONO_TYPE_CLASS:
11091                                         case MONO_TYPE_SZARRAY:
11092                                         case MONO_TYPE_ARRAY:
11093                                                 if (!mono_gc_is_moving ()) {
11094                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11095                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11096                                                         sp++;
11097                                                 } else {
11098                                                         is_const = FALSE;
11099                                                 }
11100                                                 break;
11101                                         case MONO_TYPE_I8:
11102                                         case MONO_TYPE_U8:
11103                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11104                                                 sp++;
11105                                                 break;
11106                                         case MONO_TYPE_R4:
11107                                         case MONO_TYPE_R8:
11108                                         case MONO_TYPE_VALUETYPE:
11109                                         default:
11110                                                 is_const = FALSE;
11111                                                 break;
11112                                         }
11113                                 }
11114
11115                                 if (!is_const) {
11116                                         MonoInst *load;
11117
11118                                         CHECK_STACK_OVF (1);
11119
11120                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11121                                         load->flags |= ins_flag;
11122                                         ins_flag = 0;
11123                                         *sp++ = load;
11124                                 }
11125                         }
11126
11127                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11128                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11129                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11130                         }
11131
11132                         ins_flag = 0;
11133                         ip += 5;
11134                         break;
11135                 }
11136                 case CEE_STOBJ:
11137                         CHECK_STACK (2);
11138                         sp -= 2;
11139                         CHECK_OPSIZE (5);
11140                         token = read32 (ip + 1);
11141                         klass = mini_get_class (method, token, generic_context);
11142                         CHECK_TYPELOAD (klass);
11143                         if (ins_flag & MONO_INST_VOLATILE) {
11144                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11145                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11146                         }
11147                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11148                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11149                         ins->flags |= ins_flag;
11150                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11151                                 generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
11152                                 /* insert call to write barrier */
11153                                 emit_write_barrier (cfg, sp [0], sp [1]);
11154                         }
11155                         ins_flag = 0;
11156                         ip += 5;
11157                         inline_costs += 1;
11158                         break;
11159
11160                         /*
11161                          * Array opcodes
11162                          */
11163                 case CEE_NEWARR: {
11164                         MonoInst *len_ins;
11165                         const char *data_ptr;
11166                         int data_size = 0;
11167                         guint32 field_token;
11168
11169                         CHECK_STACK (1);
11170                         --sp;
11171
11172                         CHECK_OPSIZE (5);
11173                         token = read32 (ip + 1);
11174
11175                         klass = mini_get_class (method, token, generic_context);
11176                         CHECK_TYPELOAD (klass);
11177
11178                         context_used = mini_class_check_context_used (cfg, klass);
11179
11180                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11181                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11182                                 ins->sreg1 = sp [0]->dreg;
11183                                 ins->type = STACK_I4;
11184                                 ins->dreg = alloc_ireg (cfg);
11185                                 MONO_ADD_INS (cfg->cbb, ins);
11186                                 *sp = mono_decompose_opcode (cfg, ins);
11187                         }
11188
11189                         if (context_used) {
11190                                 MonoInst *args [3];
11191                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11192                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11193
11194                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11195
11196                                 /* vtable */
11197                                 args [0] = mini_emit_get_rgctx_klass (cfg, context_used,
11198                                         array_class, MONO_RGCTX_INFO_VTABLE);
11199                                 /* array len */
11200                                 args [1] = sp [0];
11201
11202                                 if (managed_alloc)
11203                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11204                                 else
11205                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11206                         } else {
11207                                 if (cfg->opt & MONO_OPT_SHARED) {
11208                                         /* Decompose now to avoid problems with references to the domainvar */
11209                                         MonoInst *iargs [3];
11210
11211                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11212                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11213                                         iargs [2] = sp [0];
11214
11215                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11216                                 } else {
11217                                         /* Decompose later since it is needed by abcrem */
11218                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11219                                         mono_class_vtable (cfg->domain, array_type);
11220                                         CHECK_TYPELOAD (array_type);
11221
11222                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11223                                         ins->dreg = alloc_ireg_ref (cfg);
11224                                         ins->sreg1 = sp [0]->dreg;
11225                                         ins->inst_newa_class = klass;
11226                                         ins->type = STACK_OBJ;
11227                                         ins->klass = array_type;
11228                                         MONO_ADD_INS (cfg->cbb, ins);
11229                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11230                                         cfg->cbb->has_array_access = TRUE;
11231
11232                                         /* Needed so mono_emit_load_get_addr () gets called */
11233                                         mono_get_got_var (cfg);
11234                                 }
11235                         }
11236
11237                         len_ins = sp [0];
11238                         ip += 5;
11239                         *sp++ = ins;
11240                         inline_costs += 1;
11241
11242                         /* 
11243                          * we inline/optimize the initialization sequence if possible.
11244                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11245                          * for small sizes open code the memcpy
11246                          * ensure the rva field is big enough
11247                          */
11248                         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))) {
11249                                 MonoMethod *memcpy_method = get_memcpy_method ();
11250                                 MonoInst *iargs [3];
11251                                 int add_reg = alloc_ireg_mp (cfg);
11252
11253                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11254                                 if (cfg->compile_aot) {
11255                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11256                                 } else {
11257                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11258                                 }
11259                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11260                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11261                                 ip += 11;
11262                         }
11263
11264                         break;
11265                 }
11266                 case CEE_LDLEN:
11267                         CHECK_STACK (1);
11268                         --sp;
11269                         if (sp [0]->type != STACK_OBJ)
11270                                 UNVERIFIED;
11271
11272                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11273                         ins->dreg = alloc_preg (cfg);
11274                         ins->sreg1 = sp [0]->dreg;
11275                         ins->type = STACK_I4;
11276                         /* This flag will be inherited by the decomposition */
11277                         ins->flags |= MONO_INST_FAULT;
11278                         MONO_ADD_INS (cfg->cbb, ins);
11279                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11280                         cfg->cbb->has_array_access = TRUE;
11281                         ip ++;
11282                         *sp++ = ins;
11283                         break;
11284                 case CEE_LDELEMA:
11285                         CHECK_STACK (2);
11286                         sp -= 2;
11287                         CHECK_OPSIZE (5);
11288                         if (sp [0]->type != STACK_OBJ)
11289                                 UNVERIFIED;
11290
11291                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11292
11293                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11294                         CHECK_TYPELOAD (klass);
11295                         /* we need to make sure that this array is exactly the type it needs
11296                          * to be for correctness. the wrappers are lax with their usage
11297                          * so we need to ignore them here
11298                          */
11299                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11300                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11301                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11302                                 CHECK_TYPELOAD (array_class);
11303                         }
11304
11305                         readonly = FALSE;
11306                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11307                         *sp++ = ins;
11308                         ip += 5;
11309                         break;
11310                 case CEE_LDELEM:
11311                 case CEE_LDELEM_I1:
11312                 case CEE_LDELEM_U1:
11313                 case CEE_LDELEM_I2:
11314                 case CEE_LDELEM_U2:
11315                 case CEE_LDELEM_I4:
11316                 case CEE_LDELEM_U4:
11317                 case CEE_LDELEM_I8:
11318                 case CEE_LDELEM_I:
11319                 case CEE_LDELEM_R4:
11320                 case CEE_LDELEM_R8:
11321                 case CEE_LDELEM_REF: {
11322                         MonoInst *addr;
11323
11324                         CHECK_STACK (2);
11325                         sp -= 2;
11326
11327                         if (*ip == CEE_LDELEM) {
11328                                 CHECK_OPSIZE (5);
11329                                 token = read32 (ip + 1);
11330                                 klass = mini_get_class (method, token, generic_context);
11331                                 CHECK_TYPELOAD (klass);
11332                                 mono_class_init (klass);
11333                         }
11334                         else
11335                                 klass = array_access_to_klass (*ip);
11336
11337                         if (sp [0]->type != STACK_OBJ)
11338                                 UNVERIFIED;
11339
11340                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11341
11342                         if (mini_is_gsharedvt_variable_klass (klass)) {
11343                                 // FIXME-VT: OP_ICONST optimization
11344                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11345                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11346                                 ins->opcode = OP_LOADV_MEMBASE;
11347                         } else if (sp [1]->opcode == OP_ICONST) {
11348                                 int array_reg = sp [0]->dreg;
11349                                 int index_reg = sp [1]->dreg;
11350                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11351
11352                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
11353                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
11354
11355                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11356                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11357                         } else {
11358                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11359                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11360                         }
11361                         *sp++ = ins;
11362                         if (*ip == CEE_LDELEM)
11363                                 ip += 5;
11364                         else
11365                                 ++ip;
11366                         break;
11367                 }
11368                 case CEE_STELEM_I:
11369                 case CEE_STELEM_I1:
11370                 case CEE_STELEM_I2:
11371                 case CEE_STELEM_I4:
11372                 case CEE_STELEM_I8:
11373                 case CEE_STELEM_R4:
11374                 case CEE_STELEM_R8:
11375                 case CEE_STELEM_REF:
11376                 case CEE_STELEM: {
11377                         CHECK_STACK (3);
11378                         sp -= 3;
11379
11380                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11381
11382                         if (*ip == CEE_STELEM) {
11383                                 CHECK_OPSIZE (5);
11384                                 token = read32 (ip + 1);
11385                                 klass = mini_get_class (method, token, generic_context);
11386                                 CHECK_TYPELOAD (klass);
11387                                 mono_class_init (klass);
11388                         }
11389                         else
11390                                 klass = array_access_to_klass (*ip);
11391
11392                         if (sp [0]->type != STACK_OBJ)
11393                                 UNVERIFIED;
11394
11395                         emit_array_store (cfg, klass, sp, TRUE);
11396
11397                         if (*ip == CEE_STELEM)
11398                                 ip += 5;
11399                         else
11400                                 ++ip;
11401                         inline_costs += 1;
11402                         break;
11403                 }
11404                 case CEE_CKFINITE: {
11405                         CHECK_STACK (1);
11406                         --sp;
11407
11408                         if (cfg->llvm_only) {
11409                                 MonoInst *iargs [1];
11410
11411                                 iargs [0] = sp [0];
11412                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11413                         } else  {
11414                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11415                                 ins->sreg1 = sp [0]->dreg;
11416                                 ins->dreg = alloc_freg (cfg);
11417                                 ins->type = STACK_R8;
11418                                 MONO_ADD_INS (cfg->cbb, ins);
11419
11420                                 *sp++ = mono_decompose_opcode (cfg, ins);
11421                         }
11422
11423                         ++ip;
11424                         break;
11425                 }
11426                 case CEE_REFANYVAL: {
11427                         MonoInst *src_var, *src;
11428
11429                         int klass_reg = alloc_preg (cfg);
11430                         int dreg = alloc_preg (cfg);
11431
11432                         GSHAREDVT_FAILURE (*ip);
11433
11434                         CHECK_STACK (1);
11435                         MONO_INST_NEW (cfg, ins, *ip);
11436                         --sp;
11437                         CHECK_OPSIZE (5);
11438                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11439                         CHECK_TYPELOAD (klass);
11440
11441                         context_used = mini_class_check_context_used (cfg, klass);
11442
11443                         // FIXME:
11444                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11445                         if (!src_var)
11446                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11447                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11448                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11449
11450                         if (context_used) {
11451                                 MonoInst *klass_ins;
11452
11453                                 klass_ins = mini_emit_get_rgctx_klass (cfg, context_used,
11454                                                 klass, MONO_RGCTX_INFO_KLASS);
11455
11456                                 // FIXME:
11457                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11458                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11459                         } else {
11460                                 mini_emit_class_check (cfg, klass_reg, klass);
11461                         }
11462                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11463                         ins->type = STACK_MP;
11464                         ins->klass = klass;
11465                         *sp++ = ins;
11466                         ip += 5;
11467                         break;
11468                 }
11469                 case CEE_MKREFANY: {
11470                         MonoInst *loc, *addr;
11471
11472                         GSHAREDVT_FAILURE (*ip);
11473
11474                         CHECK_STACK (1);
11475                         MONO_INST_NEW (cfg, ins, *ip);
11476                         --sp;
11477                         CHECK_OPSIZE (5);
11478                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11479                         CHECK_TYPELOAD (klass);
11480
11481                         context_used = mini_class_check_context_used (cfg, klass);
11482
11483                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11484                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11485
11486                         if (context_used) {
11487                                 MonoInst *const_ins;
11488                                 int type_reg = alloc_preg (cfg);
11489
11490                                 const_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11491                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11492                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11493                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11494                         } else {
11495                                 int const_reg = alloc_preg (cfg);
11496                                 int type_reg = alloc_preg (cfg);
11497
11498                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11499                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11500                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11501                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11502                         }
11503                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11504
11505                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11506                         ins->type = STACK_VTYPE;
11507                         ins->klass = mono_defaults.typed_reference_class;
11508                         *sp++ = ins;
11509                         ip += 5;
11510                         break;
11511                 }
11512                 case CEE_LDTOKEN: {
11513                         gpointer handle;
11514                         MonoClass *handle_class;
11515
11516                         CHECK_STACK_OVF (1);
11517
11518                         CHECK_OPSIZE (5);
11519                         n = read32 (ip + 1);
11520
11521                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11522                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11523                                 handle = mono_method_get_wrapper_data (method, n);
11524                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
11525                                 if (handle_class == mono_defaults.typehandle_class)
11526                                         handle = &((MonoClass*)handle)->byval_arg;
11527                         }
11528                         else {
11529                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11530                                 CHECK_CFG_ERROR;
11531                         }
11532                         if (!handle)
11533                                 LOAD_ERROR;
11534                         mono_class_init (handle_class);
11535                         if (cfg->gshared) {
11536                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11537                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11538                                         /* This case handles ldtoken
11539                                            of an open type, like for
11540                                            typeof(Gen<>). */
11541                                         context_used = 0;
11542                                 } else if (handle_class == mono_defaults.typehandle_class) {
11543                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
11544                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11545                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11546                                 else if (handle_class == mono_defaults.methodhandle_class)
11547                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
11548                                 else
11549                                         g_assert_not_reached ();
11550                         }
11551
11552                         if ((cfg->opt & MONO_OPT_SHARED) &&
11553                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11554                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11555                                 MonoInst *addr, *vtvar, *iargs [3];
11556                                 int method_context_used;
11557
11558                                 method_context_used = mini_method_check_context_used (cfg, method);
11559
11560                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11561
11562                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11563                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11564                                 if (method_context_used) {
11565                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11566                                                 method, MONO_RGCTX_INFO_METHOD);
11567                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11568                                 } else {
11569                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11570                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11571                                 }
11572                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11573
11574                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11575
11576                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11577                         } else {
11578                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11579                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11580                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11581                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11582                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11583                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
11584
11585                                         mono_class_init (tclass);
11586                                         if (context_used) {
11587                                                 ins = mini_emit_get_rgctx_klass (cfg, context_used,
11588                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11589                                         } else if (cfg->compile_aot) {
11590                                                 if (method->wrapper_type) {
11591                                                         error_init (&error); //got to do it since there are multiple conditionals below
11592                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11593                                                                 /* Special case for static synchronized wrappers */
11594                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11595                                                         } else {
11596                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11597                                                                 /* FIXME: n is not a normal token */
11598                                                                 DISABLE_AOT (cfg);
11599                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11600                                                         }
11601                                                 } else {
11602                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11603                                                 }
11604                                         } else {
11605                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
11606                                                 CHECK_CFG_ERROR;
11607                                                 EMIT_NEW_PCONST (cfg, ins, rt);
11608                                         }
11609                                         ins->type = STACK_OBJ;
11610                                         ins->klass = cmethod->klass;
11611                                         ip += 5;
11612                                 } else {
11613                                         MonoInst *addr, *vtvar;
11614
11615                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11616
11617                                         if (context_used) {
11618                                                 if (handle_class == mono_defaults.typehandle_class) {
11619                                                         ins = mini_emit_get_rgctx_klass (cfg, context_used,
11620                                                                         mono_class_from_mono_type ((MonoType *)handle),
11621                                                                         MONO_RGCTX_INFO_TYPE);
11622                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11623                                                         ins = emit_get_rgctx_method (cfg, context_used,
11624                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
11625                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11626                                                         ins = emit_get_rgctx_field (cfg, context_used,
11627                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
11628                                                 } else {
11629                                                         g_assert_not_reached ();
11630                                                 }
11631                                         } else if (cfg->compile_aot) {
11632                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11633                                         } else {
11634                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11635                                         }
11636                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11637                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11638                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11639                                 }
11640                         }
11641
11642                         *sp++ = ins;
11643                         ip += 5;
11644                         break;
11645                 }
11646                 case CEE_THROW:
11647                         CHECK_STACK (1);
11648                         if (sp [-1]->type != STACK_OBJ)
11649                                 UNVERIFIED;
11650
11651                         MONO_INST_NEW (cfg, ins, OP_THROW);
11652                         --sp;
11653                         ins->sreg1 = sp [0]->dreg;
11654                         ip++;
11655                         cfg->cbb->out_of_line = TRUE;
11656                         MONO_ADD_INS (cfg->cbb, ins);
11657                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11658                         MONO_ADD_INS (cfg->cbb, ins);
11659                         sp = stack_start;
11660                         
11661                         link_bblock (cfg, cfg->cbb, end_bblock);
11662                         start_new_bblock = 1;
11663                         /* This can complicate code generation for llvm since the return value might not be defined */
11664                         if (COMPILE_LLVM (cfg))
11665                                 INLINE_FAILURE ("throw");
11666                         break;
11667                 case CEE_ENDFINALLY:
11668                         if (!ip_in_finally_clause (cfg, ip - header->code))
11669                                 UNVERIFIED;
11670                         /* mono_save_seq_point_info () depends on this */
11671                         if (sp != stack_start)
11672                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11673                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11674                         MONO_ADD_INS (cfg->cbb, ins);
11675                         ip++;
11676                         start_new_bblock = 1;
11677
11678                         /*
11679                          * Control will leave the method so empty the stack, otherwise
11680                          * the next basic block will start with a nonempty stack.
11681                          */
11682                         while (sp != stack_start) {
11683                                 sp--;
11684                         }
11685                         break;
11686                 case CEE_LEAVE:
11687                 case CEE_LEAVE_S: {
11688                         GList *handlers;
11689
11690                         if (*ip == CEE_LEAVE) {
11691                                 CHECK_OPSIZE (5);
11692                                 target = ip + 5 + (gint32)read32(ip + 1);
11693                         } else {
11694                                 CHECK_OPSIZE (2);
11695                                 target = ip + 2 + (signed char)(ip [1]);
11696                         }
11697
11698                         /* empty the stack */
11699                         while (sp != stack_start) {
11700                                 sp--;
11701                         }
11702
11703                         /* 
11704                          * If this leave statement is in a catch block, check for a
11705                          * pending exception, and rethrow it if necessary.
11706                          * We avoid doing this in runtime invoke wrappers, since those are called
11707                          * by native code which excepts the wrapper to catch all exceptions.
11708                          */
11709                         for (i = 0; i < header->num_clauses; ++i) {
11710                                 MonoExceptionClause *clause = &header->clauses [i];
11711
11712                                 /* 
11713                                  * Use <= in the final comparison to handle clauses with multiple
11714                                  * leave statements, like in bug #78024.
11715                                  * The ordering of the exception clauses guarantees that we find the
11716                                  * innermost clause.
11717                                  */
11718                                 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) {
11719                                         MonoInst *exc_ins;
11720                                         MonoBasicBlock *dont_throw;
11721
11722                                         /*
11723                                           MonoInst *load;
11724
11725                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11726                                         */
11727
11728                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11729
11730                                         NEW_BBLOCK (cfg, dont_throw);
11731
11732                                         /*
11733                                          * Currently, we always rethrow the abort exception, despite the 
11734                                          * fact that this is not correct. See thread6.cs for an example. 
11735                                          * But propagating the abort exception is more important than 
11736                                          * getting the sematics right.
11737                                          */
11738                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11739                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11740                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11741
11742                                         MONO_START_BB (cfg, dont_throw);
11743                                 }
11744                         }
11745
11746 #ifdef ENABLE_LLVM
11747                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
11748 #endif
11749
11750                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11751                                 GList *tmp;
11752                                 MonoExceptionClause *clause;
11753
11754                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11755                                         clause = (MonoExceptionClause *)tmp->data;
11756                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11757                                         g_assert (tblock);
11758                                         link_bblock (cfg, cfg->cbb, tblock);
11759                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11760                                         ins->inst_target_bb = tblock;
11761                                         ins->inst_eh_block = clause;
11762                                         MONO_ADD_INS (cfg->cbb, ins);
11763                                         cfg->cbb->has_call_handler = 1;
11764                                         if (COMPILE_LLVM (cfg)) {
11765                                                 MonoBasicBlock *target_bb;
11766
11767                                                 /* 
11768                                                  * Link the finally bblock with the target, since it will
11769                                                  * conceptually branch there.
11770                                                  */
11771                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
11772                                                 GET_BBLOCK (cfg, target_bb, target);
11773                                                 link_bblock (cfg, tblock, target_bb);
11774                                         }
11775                                 }
11776                                 g_list_free (handlers);
11777                         } 
11778
11779                         MONO_INST_NEW (cfg, ins, OP_BR);
11780                         MONO_ADD_INS (cfg->cbb, ins);
11781                         GET_BBLOCK (cfg, tblock, target);
11782                         link_bblock (cfg, cfg->cbb, tblock);
11783                         ins->inst_target_bb = tblock;
11784
11785                         start_new_bblock = 1;
11786
11787                         if (*ip == CEE_LEAVE)
11788                                 ip += 5;
11789                         else
11790                                 ip += 2;
11791
11792                         break;
11793                 }
11794
11795                         /*
11796                          * Mono specific opcodes
11797                          */
11798                 case MONO_CUSTOM_PREFIX: {
11799
11800                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11801
11802                         CHECK_OPSIZE (2);
11803                         switch (ip [1]) {
11804                         case CEE_MONO_ICALL: {
11805                                 gpointer func;
11806                                 MonoJitICallInfo *info;
11807
11808                                 token = read32 (ip + 2);
11809                                 func = mono_method_get_wrapper_data (method, token);
11810                                 info = mono_find_jit_icall_by_addr (func);
11811                                 if (!info)
11812                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11813                                 g_assert (info);
11814
11815                                 CHECK_STACK (info->sig->param_count);
11816                                 sp -= info->sig->param_count;
11817
11818                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11819                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11820                                         *sp++ = ins;
11821
11822                                 ip += 6;
11823                                 inline_costs += 10 * num_calls++;
11824
11825                                 break;
11826                         }
11827                         case CEE_MONO_LDPTR_CARD_TABLE:
11828                         case CEE_MONO_LDPTR_NURSERY_START:
11829                         case CEE_MONO_LDPTR_NURSERY_BITS:
11830                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
11831                                 CHECK_STACK_OVF (1);
11832
11833                                 switch (ip [1]) {
11834                                         case CEE_MONO_LDPTR_CARD_TABLE:
11835                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
11836                                                 break;
11837                                         case CEE_MONO_LDPTR_NURSERY_START:
11838                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
11839                                                 break;
11840                                         case CEE_MONO_LDPTR_NURSERY_BITS:
11841                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
11842                                                 break;
11843                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
11844                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11845                                                 break;
11846                                 }
11847
11848                                 *sp++ = ins;
11849                                 ip += 2;
11850                                 inline_costs += 10 * num_calls++;
11851                                 break;
11852                         }
11853                         case CEE_MONO_LDPTR: {
11854                                 gpointer ptr;
11855
11856                                 CHECK_STACK_OVF (1);
11857                                 CHECK_OPSIZE (6);
11858                                 token = read32 (ip + 2);
11859
11860                                 ptr = mono_method_get_wrapper_data (method, token);
11861                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11862                                 *sp++ = ins;
11863                                 ip += 6;
11864                                 inline_costs += 10 * num_calls++;
11865                                 /* Can't embed random pointers into AOT code */
11866                                 DISABLE_AOT (cfg);
11867                                 break;
11868                         }
11869                         case CEE_MONO_JIT_ICALL_ADDR: {
11870                                 MonoJitICallInfo *callinfo;
11871                                 gpointer ptr;
11872
11873                                 CHECK_STACK_OVF (1);
11874                                 CHECK_OPSIZE (6);
11875                                 token = read32 (ip + 2);
11876
11877                                 ptr = mono_method_get_wrapper_data (method, token);
11878                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11879                                 g_assert (callinfo);
11880                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11881                                 *sp++ = ins;
11882                                 ip += 6;
11883                                 inline_costs += 10 * num_calls++;
11884                                 break;
11885                         }
11886                         case CEE_MONO_ICALL_ADDR: {
11887                                 MonoMethod *cmethod;
11888                                 gpointer ptr;
11889
11890                                 CHECK_STACK_OVF (1);
11891                                 CHECK_OPSIZE (6);
11892                                 token = read32 (ip + 2);
11893
11894                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
11895
11896                                 if (cfg->compile_aot) {
11897                                         if (cfg->direct_pinvoke && ip + 6 < end && (ip [6] == CEE_POP)) {
11898                                                 /*
11899                                                  * This is generated by emit_native_wrapper () to resolve the pinvoke address
11900                                                  * before the call, its not needed when using direct pinvoke.
11901                                                  * This is not an optimization, but its used to avoid looking up pinvokes
11902                                                  * on platforms which don't support dlopen ().
11903                                                  */
11904                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11905                                         } else {
11906                                                 EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11907                                         }
11908                                 } else {
11909                                         ptr = mono_lookup_internal_call (cmethod);
11910                                         g_assert (ptr);
11911                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11912                                 }
11913                                 *sp++ = ins;
11914                                 ip += 6;
11915                                 break;
11916                         }
11917                         case CEE_MONO_VTADDR: {
11918                                 MonoInst *src_var, *src;
11919
11920                                 CHECK_STACK (1);
11921                                 --sp;
11922
11923                                 // FIXME:
11924                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11925                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11926                                 *sp++ = src;
11927                                 ip += 2;
11928                                 break;
11929                         }
11930                         case CEE_MONO_NEWOBJ: {
11931                                 MonoInst *iargs [2];
11932
11933                                 CHECK_STACK_OVF (1);
11934                                 CHECK_OPSIZE (6);
11935                                 token = read32 (ip + 2);
11936                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11937                                 mono_class_init (klass);
11938                                 NEW_DOMAINCONST (cfg, iargs [0]);
11939                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11940                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11941                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11942                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
11943                                 ip += 6;
11944                                 inline_costs += 10 * num_calls++;
11945                                 break;
11946                         }
11947                         case CEE_MONO_OBJADDR:
11948                                 CHECK_STACK (1);
11949                                 --sp;
11950                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11951                                 ins->dreg = alloc_ireg_mp (cfg);
11952                                 ins->sreg1 = sp [0]->dreg;
11953                                 ins->type = STACK_MP;
11954                                 MONO_ADD_INS (cfg->cbb, ins);
11955                                 *sp++ = ins;
11956                                 ip += 2;
11957                                 break;
11958                         case CEE_MONO_LDNATIVEOBJ:
11959                                 /*
11960                                  * Similar to LDOBJ, but instead load the unmanaged 
11961                                  * representation of the vtype to the stack.
11962                                  */
11963                                 CHECK_STACK (1);
11964                                 CHECK_OPSIZE (6);
11965                                 --sp;
11966                                 token = read32 (ip + 2);
11967                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11968                                 g_assert (klass->valuetype);
11969                                 mono_class_init (klass);
11970
11971                                 {
11972                                         MonoInst *src, *dest, *temp;
11973
11974                                         src = sp [0];
11975                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11976                                         temp->backend.is_pinvoke = 1;
11977                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11978                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11979
11980                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11981                                         dest->type = STACK_VTYPE;
11982                                         dest->klass = klass;
11983
11984                                         *sp ++ = dest;
11985                                         ip += 6;
11986                                 }
11987                                 break;
11988                         case CEE_MONO_RETOBJ: {
11989                                 /*
11990                                  * Same as RET, but return the native representation of a vtype
11991                                  * to the caller.
11992                                  */
11993                                 g_assert (cfg->ret);
11994                                 g_assert (mono_method_signature (method)->pinvoke); 
11995                                 CHECK_STACK (1);
11996                                 --sp;
11997                                 
11998                                 CHECK_OPSIZE (6);
11999                                 token = read32 (ip + 2);    
12000                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12001
12002                                 if (!cfg->vret_addr) {
12003                                         g_assert (cfg->ret_var_is_local);
12004
12005                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12006                                 } else {
12007                                         EMIT_NEW_RETLOADA (cfg, ins);
12008                                 }
12009                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12010                                 
12011                                 if (sp != stack_start)
12012                                         UNVERIFIED;
12013                                 
12014                                 MONO_INST_NEW (cfg, ins, OP_BR);
12015                                 ins->inst_target_bb = end_bblock;
12016                                 MONO_ADD_INS (cfg->cbb, ins);
12017                                 link_bblock (cfg, cfg->cbb, end_bblock);
12018                                 start_new_bblock = 1;
12019                                 ip += 6;
12020                                 break;
12021                         }
12022                         case CEE_MONO_SAVE_LMF:
12023                         case CEE_MONO_RESTORE_LMF:
12024                                 ip += 2;
12025                                 break;
12026                         case CEE_MONO_CLASSCONST:
12027                                 CHECK_STACK_OVF (1);
12028                                 CHECK_OPSIZE (6);
12029                                 token = read32 (ip + 2);
12030                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12031                                 *sp++ = ins;
12032                                 ip += 6;
12033                                 inline_costs += 10 * num_calls++;
12034                                 break;
12035                         case CEE_MONO_NOT_TAKEN:
12036                                 cfg->cbb->out_of_line = TRUE;
12037                                 ip += 2;
12038                                 break;
12039                         case CEE_MONO_TLS: {
12040                                 MonoTlsKey key;
12041
12042                                 CHECK_STACK_OVF (1);
12043                                 CHECK_OPSIZE (6);
12044                                 key = (MonoTlsKey)read32 (ip + 2);
12045                                 g_assert (key < TLS_KEY_NUM);
12046
12047                                 ins = mono_create_tls_get (cfg, key);
12048                                 g_assert (ins);
12049                                 ins->type = STACK_PTR;
12050                                 *sp++ = ins;
12051                                 ip += 6;
12052                                 break;
12053                         }
12054                         case CEE_MONO_DYN_CALL: {
12055                                 MonoCallInst *call;
12056
12057                                 /* It would be easier to call a trampoline, but that would put an
12058                                  * extra frame on the stack, confusing exception handling. So
12059                                  * implement it inline using an opcode for now.
12060                                  */
12061
12062                                 if (!cfg->dyn_call_var) {
12063                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12064                                         /* prevent it from being register allocated */
12065                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12066                                 }
12067
12068                                 /* Has to use a call inst since it local regalloc expects it */
12069                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12070                                 ins = (MonoInst*)call;
12071                                 sp -= 2;
12072                                 ins->sreg1 = sp [0]->dreg;
12073                                 ins->sreg2 = sp [1]->dreg;
12074                                 MONO_ADD_INS (cfg->cbb, ins);
12075
12076                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12077
12078                                 ip += 2;
12079                                 inline_costs += 10 * num_calls++;
12080
12081                                 break;
12082                         }
12083                         case CEE_MONO_MEMORY_BARRIER: {
12084                                 CHECK_OPSIZE (6);
12085                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12086                                 ip += 6;
12087                                 break;
12088                         }
12089                         case CEE_MONO_ATOMIC_STORE_I4: {
12090                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
12091
12092                                 CHECK_OPSIZE (6);
12093                                 CHECK_STACK (2);
12094                                 sp -= 2;
12095
12096                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
12097                                 ins->dreg = sp [0]->dreg;
12098                                 ins->sreg1 = sp [1]->dreg;
12099                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
12100                                 MONO_ADD_INS (cfg->cbb, ins);
12101
12102                                 ip += 6;
12103                                 break;
12104                         }
12105                         case CEE_MONO_JIT_ATTACH: {
12106                                 MonoInst *args [16], *domain_ins;
12107                                 MonoInst *ad_ins, *jit_tls_ins;
12108                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12109
12110                                 g_assert (!mono_threads_is_coop_enabled ());
12111
12112                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12113
12114                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12115                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12116
12117                                 ad_ins = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
12118                                 jit_tls_ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
12119
12120                                 if (ad_ins && jit_tls_ins) {
12121                                         NEW_BBLOCK (cfg, next_bb);
12122                                         NEW_BBLOCK (cfg, call_bb);
12123
12124                                         if (cfg->compile_aot) {
12125                                                 /* AOT code is only used in the root domain */
12126                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12127                                         } else {
12128                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12129                                         }
12130                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12131                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12132
12133                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12134                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12135
12136                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12137                                         MONO_START_BB (cfg, call_bb);
12138                                 }
12139
12140                                 /* AOT code is only used in the root domain */
12141                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12142                                 if (cfg->compile_aot) {
12143                                         MonoInst *addr;
12144
12145                                         /*
12146                                          * This is called on unattached threads, so it cannot go through the trampoline
12147                                          * infrastructure. Use an indirect call through a got slot initialized at load time
12148                                          * instead.
12149                                          */
12150                                         EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_JIT_THREAD_ATTACH, NULL);
12151                                         ins = mono_emit_calli (cfg, helper_sig_jit_thread_attach, args, addr, NULL, NULL);
12152                                 } else {
12153                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12154                                 }
12155                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12156
12157                                 if (next_bb)
12158                                         MONO_START_BB (cfg, next_bb);
12159
12160                                 ip += 2;
12161                                 break;
12162                         }
12163                         case CEE_MONO_JIT_DETACH: {
12164                                 MonoInst *args [16];
12165
12166                                 /* Restore the original domain */
12167                                 dreg = alloc_ireg (cfg);
12168                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12169                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12170                                 ip += 2;
12171                                 break;
12172                         }
12173                         case CEE_MONO_CALLI_EXTRA_ARG: {
12174                                 MonoInst *addr;
12175                                 MonoMethodSignature *fsig;
12176                                 MonoInst *arg;
12177
12178                                 /*
12179                                  * This is the same as CEE_CALLI, but passes an additional argument
12180                                  * to the called method in llvmonly mode.
12181                                  * This is only used by delegate invoke wrappers to call the
12182                                  * actual delegate method.
12183                                  */
12184                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12185
12186                                 CHECK_OPSIZE (6);
12187                                 token = read32 (ip + 2);
12188
12189                                 ins = NULL;
12190
12191                                 cmethod = NULL;
12192                                 CHECK_STACK (1);
12193                                 --sp;
12194                                 addr = *sp;
12195                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12196                                 CHECK_CFG_ERROR;
12197
12198                                 if (cfg->llvm_only)
12199                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12200
12201                                 n = fsig->param_count + fsig->hasthis + 1;
12202
12203                                 CHECK_STACK (n);
12204
12205                                 sp -= n;
12206                                 arg = sp [n - 1];
12207
12208                                 if (cfg->llvm_only) {
12209                                         /*
12210                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12211                                          * cconv. This is set by mono_init_delegate ().
12212                                          */
12213                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12214                                                 MonoInst *callee = addr;
12215                                                 MonoInst *call, *localloc_ins;
12216                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12217                                                 int low_bit_reg = alloc_preg (cfg);
12218
12219                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12220                                                 NEW_BBLOCK (cfg, end_bb);
12221
12222                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12223                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12224                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12225
12226                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12227                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12228                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12229                                                 /*
12230                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12231                                                  */
12232                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12233                                                 ins->dreg = alloc_preg (cfg);
12234                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12235                                                 MONO_ADD_INS (cfg->cbb, ins);
12236                                                 localloc_ins = ins;
12237                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12238                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12239                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12240
12241                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12242                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12243
12244                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12245                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12246                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12247                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12248                                                 ins->dreg = call->dreg;
12249
12250                                                 MONO_START_BB (cfg, end_bb);
12251                                         } else {
12252                                                 /* Caller uses a normal calling conv */
12253
12254                                                 MonoInst *callee = addr;
12255                                                 MonoInst *call, *localloc_ins;
12256                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12257                                                 int low_bit_reg = alloc_preg (cfg);
12258
12259                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12260                                                 NEW_BBLOCK (cfg, end_bb);
12261
12262                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12263                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12264                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12265
12266                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12267                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12268                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12269                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12270                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12271                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12272                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12273                                                 MONO_ADD_INS (cfg->cbb, addr);
12274                                                 /*
12275                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12276                                                  */
12277                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12278                                                 ins->dreg = alloc_preg (cfg);
12279                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12280                                                 MONO_ADD_INS (cfg->cbb, ins);
12281                                                 localloc_ins = ins;
12282                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12283                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12284                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12285
12286                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12287                                                 ins->dreg = call->dreg;
12288                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12289
12290                                                 MONO_START_BB (cfg, end_bb);
12291                                         }
12292                                 } else {
12293                                         /* Same as CEE_CALLI */
12294                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12295                                                 /*
12296                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12297                                                  */
12298                                                 MonoInst *callee = addr;
12299
12300                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12301                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12302                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12303                                         } else {
12304                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12305                                         }
12306                                 }
12307
12308                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12309                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12310
12311                                 CHECK_CFG_EXCEPTION;
12312
12313                                 ip += 6;
12314                                 ins_flag = 0;
12315                                 constrained_class = NULL;
12316                                 break;
12317                         }
12318                         case CEE_MONO_LDDOMAIN:
12319                                 CHECK_STACK_OVF (1);
12320                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
12321                                 ip += 2;
12322                                 *sp++ = ins;
12323                                 break;
12324                         case CEE_MONO_GET_LAST_ERROR:
12325                                 CHECK_OPSIZE (2);
12326                                 CHECK_STACK_OVF (1);
12327
12328                                 MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
12329                                 ins->dreg = alloc_dreg (cfg, STACK_I4);
12330                                 ins->type = STACK_I4;
12331                                 MONO_ADD_INS (cfg->cbb, ins);
12332
12333                                 ip += 2;
12334                                 *sp++ = ins;
12335                                 break;
12336                         default:
12337                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12338                                 break;
12339                         }
12340                         break;
12341                 }
12342
12343                 case CEE_PREFIX1: {
12344                         CHECK_OPSIZE (2);
12345                         switch (ip [1]) {
12346                         case CEE_ARGLIST: {
12347                                 /* somewhat similar to LDTOKEN */
12348                                 MonoInst *addr, *vtvar;
12349                                 CHECK_STACK_OVF (1);
12350                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12351
12352                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12353                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12354
12355                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12356                                 ins->type = STACK_VTYPE;
12357                                 ins->klass = mono_defaults.argumenthandle_class;
12358                                 *sp++ = ins;
12359                                 ip += 2;
12360                                 break;
12361                         }
12362                         case CEE_CEQ:
12363                         case CEE_CGT:
12364                         case CEE_CGT_UN:
12365                         case CEE_CLT:
12366                         case CEE_CLT_UN: {
12367                                 MonoInst *cmp, *arg1, *arg2;
12368
12369                                 CHECK_STACK (2);
12370                                 sp -= 2;
12371                                 arg1 = sp [0];
12372                                 arg2 = sp [1];
12373
12374                                 /*
12375                                  * The following transforms:
12376                                  *    CEE_CEQ    into OP_CEQ
12377                                  *    CEE_CGT    into OP_CGT
12378                                  *    CEE_CGT_UN into OP_CGT_UN
12379                                  *    CEE_CLT    into OP_CLT
12380                                  *    CEE_CLT_UN into OP_CLT_UN
12381                                  */
12382                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12383
12384                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12385                                 cmp->sreg1 = arg1->dreg;
12386                                 cmp->sreg2 = arg2->dreg;
12387                                 type_from_op (cfg, cmp, arg1, arg2);
12388                                 CHECK_TYPE (cmp);
12389                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12390                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12391                                         cmp->opcode = OP_LCOMPARE;
12392                                 else if (arg1->type == STACK_R4)
12393                                         cmp->opcode = OP_RCOMPARE;
12394                                 else if (arg1->type == STACK_R8)
12395                                         cmp->opcode = OP_FCOMPARE;
12396                                 else
12397                                         cmp->opcode = OP_ICOMPARE;
12398                                 MONO_ADD_INS (cfg->cbb, cmp);
12399                                 ins->type = STACK_I4;
12400                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
12401                                 type_from_op (cfg, ins, arg1, arg2);
12402
12403                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12404                                         /*
12405                                          * The backends expect the fceq opcodes to do the
12406                                          * comparison too.
12407                                          */
12408                                         ins->sreg1 = cmp->sreg1;
12409                                         ins->sreg2 = cmp->sreg2;
12410                                         NULLIFY_INS (cmp);
12411                                 }
12412                                 MONO_ADD_INS (cfg->cbb, ins);
12413                                 *sp++ = ins;
12414                                 ip += 2;
12415                                 break;
12416                         }
12417                         case CEE_LDFTN: {
12418                                 MonoInst *argconst;
12419                                 MonoMethod *cil_method;
12420
12421                                 CHECK_STACK_OVF (1);
12422                                 CHECK_OPSIZE (6);
12423                                 n = read32 (ip + 2);
12424                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12425                                 CHECK_CFG_ERROR;
12426
12427                                 mono_class_init (cmethod->klass);
12428
12429                                 mono_save_token_info (cfg, image, n, cmethod);
12430
12431                                 context_used = mini_method_check_context_used (cfg, cmethod);
12432
12433                                 cil_method = cmethod;
12434                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12435                                         emit_method_access_failure (cfg, method, cil_method);
12436
12437                                 if (mono_security_core_clr_enabled ())
12438                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12439
12440                                 /* 
12441                                  * Optimize the common case of ldftn+delegate creation
12442                                  */
12443                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12444                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12445                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12446                                                 MonoInst *target_ins, *handle_ins;
12447                                                 MonoMethod *invoke;
12448                                                 int invoke_context_used;
12449
12450                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12451                                                 if (!invoke || !mono_method_signature (invoke))
12452                                                         LOAD_ERROR;
12453
12454                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12455
12456                                                 target_ins = sp [-1];
12457
12458                                                 if (mono_security_core_clr_enabled ())
12459                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12460
12461                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12462                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12463                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12464                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12465                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12466                                                         }
12467                                                 }
12468
12469                                                 /* FIXME: SGEN support */
12470                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12471                                                         ip += 6;
12472                                                         if (cfg->verbose_level > 3)
12473                                                                 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));
12474                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12475                                                                 sp --;
12476                                                                 *sp = handle_ins;
12477                                                                 CHECK_CFG_EXCEPTION;
12478                                                                 ip += 5;
12479                                                                 sp ++;
12480                                                                 break;
12481                                                         }
12482                                                         ip -= 6;
12483                                                 }
12484                                         }
12485                                 }
12486
12487                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12488                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12489                                 *sp++ = ins;
12490                                 
12491                                 ip += 6;
12492                                 inline_costs += 10 * num_calls++;
12493                                 break;
12494                         }
12495                         case CEE_LDVIRTFTN: {
12496                                 MonoInst *args [2];
12497
12498                                 CHECK_STACK (1);
12499                                 CHECK_OPSIZE (6);
12500                                 n = read32 (ip + 2);
12501                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12502                                 CHECK_CFG_ERROR;
12503
12504                                 mono_class_init (cmethod->klass);
12505  
12506                                 context_used = mini_method_check_context_used (cfg, cmethod);
12507
12508                                 if (mono_security_core_clr_enabled ())
12509                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12510
12511                                 /*
12512                                  * Optimize the common case of ldvirtftn+delegate creation
12513                                  */
12514                                 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)) {
12515                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12516                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12517                                                 MonoInst *target_ins, *handle_ins;
12518                                                 MonoMethod *invoke;
12519                                                 int invoke_context_used;
12520                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12521
12522                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12523                                                 if (!invoke || !mono_method_signature (invoke))
12524                                                         LOAD_ERROR;
12525
12526                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12527
12528                                                 target_ins = sp [-1];
12529
12530                                                 if (mono_security_core_clr_enabled ())
12531                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12532
12533                                                 /* FIXME: SGEN support */
12534                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12535                                                         ip += 6;
12536                                                         if (cfg->verbose_level > 3)
12537                                                                 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));
12538                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12539                                                                 sp -= 2;
12540                                                                 *sp = handle_ins;
12541                                                                 CHECK_CFG_EXCEPTION;
12542                                                                 ip += 5;
12543                                                                 sp ++;
12544                                                                 break;
12545                                                         }
12546                                                         ip -= 6;
12547                                                 }
12548                                         }
12549                                 }
12550
12551                                 --sp;
12552                                 args [0] = *sp;
12553
12554                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12555                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12556
12557                                 if (context_used)
12558                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12559                                 else
12560                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12561
12562                                 ip += 6;
12563                                 inline_costs += 10 * num_calls++;
12564                                 break;
12565                         }
12566                         case CEE_LDARG:
12567                                 CHECK_STACK_OVF (1);
12568                                 CHECK_OPSIZE (4);
12569                                 n = read16 (ip + 2);
12570                                 CHECK_ARG (n);
12571                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12572                                 *sp++ = ins;
12573                                 ip += 4;
12574                                 break;
12575                         case CEE_LDARGA:
12576                                 CHECK_STACK_OVF (1);
12577                                 CHECK_OPSIZE (4);
12578                                 n = read16 (ip + 2);
12579                                 CHECK_ARG (n);
12580                                 NEW_ARGLOADA (cfg, ins, n);
12581                                 MONO_ADD_INS (cfg->cbb, ins);
12582                                 *sp++ = ins;
12583                                 ip += 4;
12584                                 break;
12585                         case CEE_STARG:
12586                                 CHECK_STACK (1);
12587                                 --sp;
12588                                 CHECK_OPSIZE (4);
12589                                 n = read16 (ip + 2);
12590                                 CHECK_ARG (n);
12591                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12592                                         UNVERIFIED;
12593                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12594                                 ip += 4;
12595                                 break;
12596                         case CEE_LDLOC:
12597                                 CHECK_STACK_OVF (1);
12598                                 CHECK_OPSIZE (4);
12599                                 n = read16 (ip + 2);
12600                                 CHECK_LOCAL (n);
12601                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12602                                 *sp++ = ins;
12603                                 ip += 4;
12604                                 break;
12605                         case CEE_LDLOCA: {
12606                                 unsigned char *tmp_ip;
12607                                 CHECK_STACK_OVF (1);
12608                                 CHECK_OPSIZE (4);
12609                                 n = read16 (ip + 2);
12610                                 CHECK_LOCAL (n);
12611
12612                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12613                                         ip = tmp_ip;
12614                                         inline_costs += 1;
12615                                         break;
12616                                 }                       
12617                                 
12618                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12619                                 *sp++ = ins;
12620                                 ip += 4;
12621                                 break;
12622                         }
12623                         case CEE_STLOC:
12624                                 CHECK_STACK (1);
12625                                 --sp;
12626                                 CHECK_OPSIZE (4);
12627                                 n = read16 (ip + 2);
12628                                 CHECK_LOCAL (n);
12629                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12630                                         UNVERIFIED;
12631                                 emit_stloc_ir (cfg, sp, header, n);
12632                                 ip += 4;
12633                                 inline_costs += 1;
12634                                 break;
12635                         case CEE_LOCALLOC: {
12636                                 CHECK_STACK (1);
12637                                 MonoBasicBlock *non_zero_bb, *end_bb;
12638                                 int alloc_ptr = alloc_preg (cfg);
12639                                 --sp;
12640                                 if (sp != stack_start) 
12641                                         UNVERIFIED;
12642                                 if (cfg->method != method) 
12643                                         /* 
12644                                          * Inlining this into a loop in a parent could lead to 
12645                                          * stack overflows which is different behavior than the
12646                                          * non-inlined case, thus disable inlining in this case.
12647                                          */
12648                                         INLINE_FAILURE("localloc");
12649
12650                                 NEW_BBLOCK (cfg, non_zero_bb);
12651                                 NEW_BBLOCK (cfg, end_bb);
12652
12653                                 /* if size != zero */
12654                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
12655                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
12656
12657                                 //size is zero, so result is NULL
12658                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
12659                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12660
12661                                 MONO_START_BB (cfg, non_zero_bb);
12662                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12663                                 ins->dreg = alloc_ptr;
12664                                 ins->sreg1 = sp [0]->dreg;
12665                                 ins->type = STACK_PTR;
12666                                 MONO_ADD_INS (cfg->cbb, ins);
12667
12668                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12669                                 if (init_locals)
12670                                         ins->flags |= MONO_INST_INIT;
12671
12672                                 MONO_START_BB (cfg, end_bb);
12673                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
12674                                 ins->type = STACK_PTR;
12675
12676                                 *sp++ = ins;
12677                                 ip += 2;
12678                                 break;
12679                         }
12680                         case CEE_ENDFILTER: {
12681                                 MonoExceptionClause *clause, *nearest;
12682                                 int cc;
12683
12684                                 CHECK_STACK (1);
12685                                 --sp;
12686                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12687                                         UNVERIFIED;
12688                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12689                                 ins->sreg1 = (*sp)->dreg;
12690                                 MONO_ADD_INS (cfg->cbb, ins);
12691                                 start_new_bblock = 1;
12692                                 ip += 2;
12693
12694                                 nearest = NULL;
12695                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12696                                         clause = &header->clauses [cc];
12697                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12698                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12699                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12700                                                 nearest = clause;
12701                                 }
12702                                 g_assert (nearest);
12703                                 if ((ip - header->code) != nearest->handler_offset)
12704                                         UNVERIFIED;
12705
12706                                 break;
12707                         }
12708                         case CEE_UNALIGNED_:
12709                                 ins_flag |= MONO_INST_UNALIGNED;
12710                                 /* FIXME: record alignment? we can assume 1 for now */
12711                                 CHECK_OPSIZE (3);
12712                                 ip += 3;
12713                                 break;
12714                         case CEE_VOLATILE_:
12715                                 ins_flag |= MONO_INST_VOLATILE;
12716                                 ip += 2;
12717                                 break;
12718                         case CEE_TAIL_:
12719                                 ins_flag   |= MONO_INST_TAILCALL;
12720                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12721                                 /* Can't inline tail calls at this time */
12722                                 inline_costs += 100000;
12723                                 ip += 2;
12724                                 break;
12725                         case CEE_INITOBJ:
12726                                 CHECK_STACK (1);
12727                                 --sp;
12728                                 CHECK_OPSIZE (6);
12729                                 token = read32 (ip + 2);
12730                                 klass = mini_get_class (method, token, generic_context);
12731                                 CHECK_TYPELOAD (klass);
12732                                 if (generic_class_is_reference_type (cfg, klass))
12733                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12734                                 else
12735                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12736                                 ip += 6;
12737                                 inline_costs += 1;
12738                                 break;
12739                         case CEE_CONSTRAINED_:
12740                                 CHECK_OPSIZE (6);
12741                                 token = read32 (ip + 2);
12742                                 constrained_class = mini_get_class (method, token, generic_context);
12743                                 CHECK_TYPELOAD (constrained_class);
12744                                 ip += 6;
12745                                 break;
12746                         case CEE_CPBLK:
12747                         case CEE_INITBLK: {
12748                                 MonoInst *iargs [3];
12749                                 CHECK_STACK (3);
12750                                 sp -= 3;
12751
12752                                 /* Skip optimized paths for volatile operations. */
12753                                 if ((ip [1] == CEE_CPBLK) && !(ins_flag & MONO_INST_VOLATILE) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
12754                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12755                                 } else if ((ip [1] == CEE_INITBLK) && !(ins_flag & MONO_INST_VOLATILE) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5) && (sp [1]->opcode == OP_ICONST) && (sp [1]->inst_c0 == 0)) {
12756                                         /* emit_memset only works when val == 0 */
12757                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12758                                 } else {
12759                                         MonoInst *call;
12760                                         iargs [0] = sp [0];
12761                                         iargs [1] = sp [1];
12762                                         iargs [2] = sp [2];
12763                                         if (ip [1] == CEE_CPBLK) {
12764                                                 /*
12765                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12766                                                  * and release barriers for cpblk. It is technically both a load and
12767                                                  * store operation, so it seems like that's the sensible thing to do.
12768                                                  *
12769                                                  * FIXME: We emit full barriers on both sides of the operation for
12770                                                  * simplicity. We should have a separate atomic memcpy method instead.
12771                                                  */
12772                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12773
12774                                                 if (ins_flag & MONO_INST_VOLATILE)
12775                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12776
12777                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12778                                                 call->flags |= ins_flag;
12779
12780                                                 if (ins_flag & MONO_INST_VOLATILE)
12781                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12782                                         } else {
12783                                                 MonoMethod *memset_method = get_memset_method ();
12784                                                 if (ins_flag & MONO_INST_VOLATILE) {
12785                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12786                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12787                                                 }
12788                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12789                                                 call->flags |= ins_flag;
12790                                         }
12791                                 }
12792                                 ip += 2;
12793                                 ins_flag = 0;
12794                                 inline_costs += 1;
12795                                 break;
12796                         }
12797                         case CEE_NO_:
12798                                 CHECK_OPSIZE (3);
12799                                 if (ip [2] & 0x1)
12800                                         ins_flag |= MONO_INST_NOTYPECHECK;
12801                                 if (ip [2] & 0x2)
12802                                         ins_flag |= MONO_INST_NORANGECHECK;
12803                                 /* we ignore the no-nullcheck for now since we
12804                                  * really do it explicitly only when doing callvirt->call
12805                                  */
12806                                 ip += 3;
12807                                 break;
12808                         case CEE_RETHROW: {
12809                                 MonoInst *load;
12810                                 int handler_offset = -1;
12811
12812                                 for (i = 0; i < header->num_clauses; ++i) {
12813                                         MonoExceptionClause *clause = &header->clauses [i];
12814                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12815                                                 handler_offset = clause->handler_offset;
12816                                                 break;
12817                                         }
12818                                 }
12819
12820                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12821
12822                                 if (handler_offset == -1)
12823                                         UNVERIFIED;
12824
12825                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12826                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12827                                 ins->sreg1 = load->dreg;
12828                                 MONO_ADD_INS (cfg->cbb, ins);
12829
12830                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12831                                 MONO_ADD_INS (cfg->cbb, ins);
12832
12833                                 sp = stack_start;
12834                                 link_bblock (cfg, cfg->cbb, end_bblock);
12835                                 start_new_bblock = 1;
12836                                 ip += 2;
12837                                 break;
12838                         }
12839                         case CEE_SIZEOF: {
12840                                 guint32 val;
12841                                 int ialign;
12842
12843                                 CHECK_STACK_OVF (1);
12844                                 CHECK_OPSIZE (6);
12845                                 token = read32 (ip + 2);
12846                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12847                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12848                                         CHECK_CFG_ERROR;
12849
12850                                         val = mono_type_size (type, &ialign);
12851                                 } else {
12852                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12853                                         CHECK_TYPELOAD (klass);
12854
12855                                         val = mono_type_size (&klass->byval_arg, &ialign);
12856
12857                                         if (mini_is_gsharedvt_klass (klass))
12858                                                 GSHAREDVT_FAILURE (*ip);
12859                                 }
12860                                 EMIT_NEW_ICONST (cfg, ins, val);
12861                                 *sp++= ins;
12862                                 ip += 6;
12863                                 break;
12864                         }
12865                         case CEE_REFANYTYPE: {
12866                                 MonoInst *src_var, *src;
12867
12868                                 GSHAREDVT_FAILURE (*ip);
12869
12870                                 CHECK_STACK (1);
12871                                 --sp;
12872
12873                                 // FIXME:
12874                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12875                                 if (!src_var)
12876                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12877                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12878                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12879                                 *sp++ = ins;
12880                                 ip += 2;
12881                                 break;
12882                         }
12883                         case CEE_READONLY_:
12884                                 readonly = TRUE;
12885                                 ip += 2;
12886                                 break;
12887
12888                         case CEE_UNUSED56:
12889                         case CEE_UNUSED57:
12890                         case CEE_UNUSED70:
12891                         case CEE_UNUSED:
12892                         case CEE_UNUSED99:
12893                                 UNVERIFIED;
12894                                 
12895                         default:
12896                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12897                                 UNVERIFIED;
12898                         }
12899                         break;
12900                 }
12901                 case CEE_UNUSED58:
12902                 case CEE_UNUSED1:
12903                         UNVERIFIED;
12904
12905                 default:
12906                         g_warning ("opcode 0x%02x not handled", *ip);
12907                         UNVERIFIED;
12908                 }
12909         }
12910         if (start_new_bblock != 1)
12911                 UNVERIFIED;
12912
12913         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
12914         if (cfg->cbb->next_bb) {
12915                 /* This could already be set because of inlining, #693905 */
12916                 MonoBasicBlock *bb = cfg->cbb;
12917
12918                 while (bb->next_bb)
12919                         bb = bb->next_bb;
12920                 bb->next_bb = end_bblock;
12921         } else {
12922                 cfg->cbb->next_bb = end_bblock;
12923         }
12924
12925         if (cfg->method == method && cfg->domainvar) {
12926                 MonoInst *store;
12927                 MonoInst *get_domain;
12928
12929                 cfg->cbb = init_localsbb;
12930
12931                 get_domain = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
12932                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12933                 MONO_ADD_INS (cfg->cbb, store);
12934         }
12935
12936 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12937         if (cfg->compile_aot)
12938                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12939                 mono_get_got_var (cfg);
12940 #endif
12941
12942         if (cfg->method == method && cfg->got_var)
12943                 mono_emit_load_got_addr (cfg);
12944
12945         if (init_localsbb) {
12946                 cfg->cbb = init_localsbb;
12947                 cfg->ip = NULL;
12948                 for (i = 0; i < header->num_locals; ++i) {
12949                         emit_init_local (cfg, i, header->locals [i], init_locals);
12950                 }
12951         }
12952
12953         if (cfg->init_ref_vars && cfg->method == method) {
12954                 /* Emit initialization for ref vars */
12955                 // FIXME: Avoid duplication initialization for IL locals.
12956                 for (i = 0; i < cfg->num_varinfo; ++i) {
12957                         MonoInst *ins = cfg->varinfo [i];
12958
12959                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12960                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12961                 }
12962         }
12963
12964         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
12965                 cfg->cbb = init_localsbb;
12966                 emit_push_lmf (cfg);
12967         }
12968
12969         cfg->cbb = init_localsbb;
12970         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12971
12972         if (seq_points) {
12973                 MonoBasicBlock *bb;
12974
12975                 /*
12976                  * Make seq points at backward branch targets interruptable.
12977                  */
12978                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12979                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12980                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12981         }
12982
12983         /* Add a sequence point for method entry/exit events */
12984         if (seq_points && cfg->gen_sdb_seq_points) {
12985                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12986                 MONO_ADD_INS (init_localsbb, ins);
12987                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12988                 MONO_ADD_INS (cfg->bb_exit, ins);
12989         }
12990
12991         /*
12992          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12993          * the code they refer to was dead (#11880).
12994          */
12995         if (sym_seq_points) {
12996                 for (i = 0; i < header->code_size; ++i) {
12997                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12998                                 MonoInst *ins;
12999
13000                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13001                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13002                         }
13003                 }
13004         }
13005
13006         cfg->ip = NULL;
13007
13008         if (cfg->method == method) {
13009                 MonoBasicBlock *bb;
13010                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13011                         if (bb == cfg->bb_init)
13012                                 bb->region = -1;
13013                         else
13014                                 bb->region = mono_find_block_region (cfg, bb->real_offset);
13015                         if (cfg->spvars)
13016                                 mono_create_spvar_for_region (cfg, bb->region);
13017                         if (cfg->verbose_level > 2)
13018                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13019                 }
13020         } else {
13021                 MonoBasicBlock *bb;
13022                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
13023                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
13024                         bb->real_offset = inline_offset;
13025                 }
13026         }
13027
13028         if (inline_costs < 0) {
13029                 char *mname;
13030
13031                 /* Method is too large */
13032                 mname = mono_method_full_name (method, TRUE);
13033                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13034                 g_free (mname);
13035         }
13036
13037         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13038                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13039
13040         goto cleanup;
13041
13042 mono_error_exit:
13043         g_assert (!mono_error_ok (&cfg->error));
13044         goto cleanup;
13045  
13046  exception_exit:
13047         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13048         goto cleanup;
13049
13050  unverified:
13051         set_exception_type_from_invalid_il (cfg, method, ip);
13052         goto cleanup;
13053
13054  cleanup:
13055         g_slist_free (class_inits);
13056         mono_basic_block_free (original_bb);
13057         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13058         if (cfg->exception_type)
13059                 return -1;
13060         else
13061                 return inline_costs;
13062 }
13063
13064 static int
13065 store_membase_reg_to_store_membase_imm (int opcode)
13066 {
13067         switch (opcode) {
13068         case OP_STORE_MEMBASE_REG:
13069                 return OP_STORE_MEMBASE_IMM;
13070         case OP_STOREI1_MEMBASE_REG:
13071                 return OP_STOREI1_MEMBASE_IMM;
13072         case OP_STOREI2_MEMBASE_REG:
13073                 return OP_STOREI2_MEMBASE_IMM;
13074         case OP_STOREI4_MEMBASE_REG:
13075                 return OP_STOREI4_MEMBASE_IMM;
13076         case OP_STOREI8_MEMBASE_REG:
13077                 return OP_STOREI8_MEMBASE_IMM;
13078         default:
13079                 g_assert_not_reached ();
13080         }
13081
13082         return -1;
13083 }               
13084
13085 int
13086 mono_op_to_op_imm (int opcode)
13087 {
13088         switch (opcode) {
13089         case OP_IADD:
13090                 return OP_IADD_IMM;
13091         case OP_ISUB:
13092                 return OP_ISUB_IMM;
13093         case OP_IDIV:
13094                 return OP_IDIV_IMM;
13095         case OP_IDIV_UN:
13096                 return OP_IDIV_UN_IMM;
13097         case OP_IREM:
13098                 return OP_IREM_IMM;
13099         case OP_IREM_UN:
13100                 return OP_IREM_UN_IMM;
13101         case OP_IMUL:
13102                 return OP_IMUL_IMM;
13103         case OP_IAND:
13104                 return OP_IAND_IMM;
13105         case OP_IOR:
13106                 return OP_IOR_IMM;
13107         case OP_IXOR:
13108                 return OP_IXOR_IMM;
13109         case OP_ISHL:
13110                 return OP_ISHL_IMM;
13111         case OP_ISHR:
13112                 return OP_ISHR_IMM;
13113         case OP_ISHR_UN:
13114                 return OP_ISHR_UN_IMM;
13115
13116         case OP_LADD:
13117                 return OP_LADD_IMM;
13118         case OP_LSUB:
13119                 return OP_LSUB_IMM;
13120         case OP_LAND:
13121                 return OP_LAND_IMM;
13122         case OP_LOR:
13123                 return OP_LOR_IMM;
13124         case OP_LXOR:
13125                 return OP_LXOR_IMM;
13126         case OP_LSHL:
13127                 return OP_LSHL_IMM;
13128         case OP_LSHR:
13129                 return OP_LSHR_IMM;
13130         case OP_LSHR_UN:
13131                 return OP_LSHR_UN_IMM;
13132 #if SIZEOF_REGISTER == 8
13133         case OP_LREM:
13134                 return OP_LREM_IMM;
13135 #endif
13136
13137         case OP_COMPARE:
13138                 return OP_COMPARE_IMM;
13139         case OP_ICOMPARE:
13140                 return OP_ICOMPARE_IMM;
13141         case OP_LCOMPARE:
13142                 return OP_LCOMPARE_IMM;
13143
13144         case OP_STORE_MEMBASE_REG:
13145                 return OP_STORE_MEMBASE_IMM;
13146         case OP_STOREI1_MEMBASE_REG:
13147                 return OP_STOREI1_MEMBASE_IMM;
13148         case OP_STOREI2_MEMBASE_REG:
13149                 return OP_STOREI2_MEMBASE_IMM;
13150         case OP_STOREI4_MEMBASE_REG:
13151                 return OP_STOREI4_MEMBASE_IMM;
13152
13153 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13154         case OP_X86_PUSH:
13155                 return OP_X86_PUSH_IMM;
13156         case OP_X86_COMPARE_MEMBASE_REG:
13157                 return OP_X86_COMPARE_MEMBASE_IMM;
13158 #endif
13159 #if defined(TARGET_AMD64)
13160         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13161                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13162 #endif
13163         case OP_VOIDCALL_REG:
13164                 return OP_VOIDCALL;
13165         case OP_CALL_REG:
13166                 return OP_CALL;
13167         case OP_LCALL_REG:
13168                 return OP_LCALL;
13169         case OP_FCALL_REG:
13170                 return OP_FCALL;
13171         case OP_LOCALLOC:
13172                 return OP_LOCALLOC_IMM;
13173         }
13174
13175         return -1;
13176 }
13177
13178 static int
13179 ldind_to_load_membase (int opcode)
13180 {
13181         switch (opcode) {
13182         case CEE_LDIND_I1:
13183                 return OP_LOADI1_MEMBASE;
13184         case CEE_LDIND_U1:
13185                 return OP_LOADU1_MEMBASE;
13186         case CEE_LDIND_I2:
13187                 return OP_LOADI2_MEMBASE;
13188         case CEE_LDIND_U2:
13189                 return OP_LOADU2_MEMBASE;
13190         case CEE_LDIND_I4:
13191                 return OP_LOADI4_MEMBASE;
13192         case CEE_LDIND_U4:
13193                 return OP_LOADU4_MEMBASE;
13194         case CEE_LDIND_I:
13195                 return OP_LOAD_MEMBASE;
13196         case CEE_LDIND_REF:
13197                 return OP_LOAD_MEMBASE;
13198         case CEE_LDIND_I8:
13199                 return OP_LOADI8_MEMBASE;
13200         case CEE_LDIND_R4:
13201                 return OP_LOADR4_MEMBASE;
13202         case CEE_LDIND_R8:
13203                 return OP_LOADR8_MEMBASE;
13204         default:
13205                 g_assert_not_reached ();
13206         }
13207
13208         return -1;
13209 }
13210
13211 static int
13212 stind_to_store_membase (int opcode)
13213 {
13214         switch (opcode) {
13215         case CEE_STIND_I1:
13216                 return OP_STOREI1_MEMBASE_REG;
13217         case CEE_STIND_I2:
13218                 return OP_STOREI2_MEMBASE_REG;
13219         case CEE_STIND_I4:
13220                 return OP_STOREI4_MEMBASE_REG;
13221         case CEE_STIND_I:
13222         case CEE_STIND_REF:
13223                 return OP_STORE_MEMBASE_REG;
13224         case CEE_STIND_I8:
13225                 return OP_STOREI8_MEMBASE_REG;
13226         case CEE_STIND_R4:
13227                 return OP_STORER4_MEMBASE_REG;
13228         case CEE_STIND_R8:
13229                 return OP_STORER8_MEMBASE_REG;
13230         default:
13231                 g_assert_not_reached ();
13232         }
13233
13234         return -1;
13235 }
13236
13237 int
13238 mono_load_membase_to_load_mem (int opcode)
13239 {
13240         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13241 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13242         switch (opcode) {
13243         case OP_LOAD_MEMBASE:
13244                 return OP_LOAD_MEM;
13245         case OP_LOADU1_MEMBASE:
13246                 return OP_LOADU1_MEM;
13247         case OP_LOADU2_MEMBASE:
13248                 return OP_LOADU2_MEM;
13249         case OP_LOADI4_MEMBASE:
13250                 return OP_LOADI4_MEM;
13251         case OP_LOADU4_MEMBASE:
13252                 return OP_LOADU4_MEM;
13253 #if SIZEOF_REGISTER == 8
13254         case OP_LOADI8_MEMBASE:
13255                 return OP_LOADI8_MEM;
13256 #endif
13257         }
13258 #endif
13259
13260         return -1;
13261 }
13262
13263 static inline int
13264 op_to_op_dest_membase (int store_opcode, int opcode)
13265 {
13266 #if defined(TARGET_X86)
13267         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13268                 return -1;
13269
13270         switch (opcode) {
13271         case OP_IADD:
13272                 return OP_X86_ADD_MEMBASE_REG;
13273         case OP_ISUB:
13274                 return OP_X86_SUB_MEMBASE_REG;
13275         case OP_IAND:
13276                 return OP_X86_AND_MEMBASE_REG;
13277         case OP_IOR:
13278                 return OP_X86_OR_MEMBASE_REG;
13279         case OP_IXOR:
13280                 return OP_X86_XOR_MEMBASE_REG;
13281         case OP_ADD_IMM:
13282         case OP_IADD_IMM:
13283                 return OP_X86_ADD_MEMBASE_IMM;
13284         case OP_SUB_IMM:
13285         case OP_ISUB_IMM:
13286                 return OP_X86_SUB_MEMBASE_IMM;
13287         case OP_AND_IMM:
13288         case OP_IAND_IMM:
13289                 return OP_X86_AND_MEMBASE_IMM;
13290         case OP_OR_IMM:
13291         case OP_IOR_IMM:
13292                 return OP_X86_OR_MEMBASE_IMM;
13293         case OP_XOR_IMM:
13294         case OP_IXOR_IMM:
13295                 return OP_X86_XOR_MEMBASE_IMM;
13296         case OP_MOVE:
13297                 return OP_NOP;
13298         }
13299 #endif
13300
13301 #if defined(TARGET_AMD64)
13302         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13303                 return -1;
13304
13305         switch (opcode) {
13306         case OP_IADD:
13307                 return OP_X86_ADD_MEMBASE_REG;
13308         case OP_ISUB:
13309                 return OP_X86_SUB_MEMBASE_REG;
13310         case OP_IAND:
13311                 return OP_X86_AND_MEMBASE_REG;
13312         case OP_IOR:
13313                 return OP_X86_OR_MEMBASE_REG;
13314         case OP_IXOR:
13315                 return OP_X86_XOR_MEMBASE_REG;
13316         case OP_IADD_IMM:
13317                 return OP_X86_ADD_MEMBASE_IMM;
13318         case OP_ISUB_IMM:
13319                 return OP_X86_SUB_MEMBASE_IMM;
13320         case OP_IAND_IMM:
13321                 return OP_X86_AND_MEMBASE_IMM;
13322         case OP_IOR_IMM:
13323                 return OP_X86_OR_MEMBASE_IMM;
13324         case OP_IXOR_IMM:
13325                 return OP_X86_XOR_MEMBASE_IMM;
13326         case OP_LADD:
13327                 return OP_AMD64_ADD_MEMBASE_REG;
13328         case OP_LSUB:
13329                 return OP_AMD64_SUB_MEMBASE_REG;
13330         case OP_LAND:
13331                 return OP_AMD64_AND_MEMBASE_REG;
13332         case OP_LOR:
13333                 return OP_AMD64_OR_MEMBASE_REG;
13334         case OP_LXOR:
13335                 return OP_AMD64_XOR_MEMBASE_REG;
13336         case OP_ADD_IMM:
13337         case OP_LADD_IMM:
13338                 return OP_AMD64_ADD_MEMBASE_IMM;
13339         case OP_SUB_IMM:
13340         case OP_LSUB_IMM:
13341                 return OP_AMD64_SUB_MEMBASE_IMM;
13342         case OP_AND_IMM:
13343         case OP_LAND_IMM:
13344                 return OP_AMD64_AND_MEMBASE_IMM;
13345         case OP_OR_IMM:
13346         case OP_LOR_IMM:
13347                 return OP_AMD64_OR_MEMBASE_IMM;
13348         case OP_XOR_IMM:
13349         case OP_LXOR_IMM:
13350                 return OP_AMD64_XOR_MEMBASE_IMM;
13351         case OP_MOVE:
13352                 return OP_NOP;
13353         }
13354 #endif
13355
13356         return -1;
13357 }
13358
13359 static inline int
13360 op_to_op_store_membase (int store_opcode, int opcode)
13361 {
13362 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13363         switch (opcode) {
13364         case OP_ICEQ:
13365                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13366                         return OP_X86_SETEQ_MEMBASE;
13367         case OP_CNE:
13368                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13369                         return OP_X86_SETNE_MEMBASE;
13370         }
13371 #endif
13372
13373         return -1;
13374 }
13375
13376 static inline int
13377 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13378 {
13379 #ifdef TARGET_X86
13380         /* FIXME: This has sign extension issues */
13381         /*
13382         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13383                 return OP_X86_COMPARE_MEMBASE8_IMM;
13384         */
13385
13386         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13387                 return -1;
13388
13389         switch (opcode) {
13390         case OP_X86_PUSH:
13391                 return OP_X86_PUSH_MEMBASE;
13392         case OP_COMPARE_IMM:
13393         case OP_ICOMPARE_IMM:
13394                 return OP_X86_COMPARE_MEMBASE_IMM;
13395         case OP_COMPARE:
13396         case OP_ICOMPARE:
13397                 return OP_X86_COMPARE_MEMBASE_REG;
13398         }
13399 #endif
13400
13401 #ifdef TARGET_AMD64
13402         /* FIXME: This has sign extension issues */
13403         /*
13404         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13405                 return OP_X86_COMPARE_MEMBASE8_IMM;
13406         */
13407
13408         switch (opcode) {
13409         case OP_X86_PUSH:
13410                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13411                         return OP_X86_PUSH_MEMBASE;
13412                 break;
13413                 /* FIXME: This only works for 32 bit immediates
13414         case OP_COMPARE_IMM:
13415         case OP_LCOMPARE_IMM:
13416                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13417                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13418                 */
13419         case OP_ICOMPARE_IMM:
13420                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13421                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13422                 break;
13423         case OP_COMPARE:
13424         case OP_LCOMPARE:
13425                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
13426                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13427                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13428                         return OP_AMD64_COMPARE_MEMBASE_REG;
13429                 break;
13430         case OP_ICOMPARE:
13431                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13432                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13433                 break;
13434         }
13435 #endif
13436
13437         return -1;
13438 }
13439
13440 static inline int
13441 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
13442 {
13443 #ifdef TARGET_X86
13444         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13445                 return -1;
13446         
13447         switch (opcode) {
13448         case OP_COMPARE:
13449         case OP_ICOMPARE:
13450                 return OP_X86_COMPARE_REG_MEMBASE;
13451         case OP_IADD:
13452                 return OP_X86_ADD_REG_MEMBASE;
13453         case OP_ISUB:
13454                 return OP_X86_SUB_REG_MEMBASE;
13455         case OP_IAND:
13456                 return OP_X86_AND_REG_MEMBASE;
13457         case OP_IOR:
13458                 return OP_X86_OR_REG_MEMBASE;
13459         case OP_IXOR:
13460                 return OP_X86_XOR_REG_MEMBASE;
13461         }
13462 #endif
13463
13464 #ifdef TARGET_AMD64
13465         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
13466                 switch (opcode) {
13467                 case OP_ICOMPARE:
13468                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13469                 case OP_IADD:
13470                         return OP_X86_ADD_REG_MEMBASE;
13471                 case OP_ISUB:
13472                         return OP_X86_SUB_REG_MEMBASE;
13473                 case OP_IAND:
13474                         return OP_X86_AND_REG_MEMBASE;
13475                 case OP_IOR:
13476                         return OP_X86_OR_REG_MEMBASE;
13477                 case OP_IXOR:
13478                         return OP_X86_XOR_REG_MEMBASE;
13479                 }
13480         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
13481                 switch (opcode) {
13482                 case OP_COMPARE:
13483                 case OP_LCOMPARE:
13484                         return OP_AMD64_COMPARE_REG_MEMBASE;
13485                 case OP_LADD:
13486                         return OP_AMD64_ADD_REG_MEMBASE;
13487                 case OP_LSUB:
13488                         return OP_AMD64_SUB_REG_MEMBASE;
13489                 case OP_LAND:
13490                         return OP_AMD64_AND_REG_MEMBASE;
13491                 case OP_LOR:
13492                         return OP_AMD64_OR_REG_MEMBASE;
13493                 case OP_LXOR:
13494                         return OP_AMD64_XOR_REG_MEMBASE;
13495                 }
13496         }
13497 #endif
13498
13499         return -1;
13500 }
13501
13502 int
13503 mono_op_to_op_imm_noemul (int opcode)
13504 {
13505         switch (opcode) {
13506 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13507         case OP_LSHR:
13508         case OP_LSHL:
13509         case OP_LSHR_UN:
13510                 return -1;
13511 #endif
13512 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13513         case OP_IDIV:
13514         case OP_IDIV_UN:
13515         case OP_IREM:
13516         case OP_IREM_UN:
13517                 return -1;
13518 #endif
13519 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13520         case OP_IMUL:
13521                 return -1;
13522 #endif
13523         default:
13524                 return mono_op_to_op_imm (opcode);
13525         }
13526 }
13527
13528 /**
13529  * mono_handle_global_vregs:
13530  *
13531  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13532  * for them.
13533  */
13534 void
13535 mono_handle_global_vregs (MonoCompile *cfg)
13536 {
13537         gint32 *vreg_to_bb;
13538         MonoBasicBlock *bb;
13539         int i, pos;
13540
13541         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13542
13543 #ifdef MONO_ARCH_SIMD_INTRINSICS
13544         if (cfg->uses_simd_intrinsics)
13545                 mono_simd_simplify_indirection (cfg);
13546 #endif
13547
13548         /* Find local vregs used in more than one bb */
13549         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13550                 MonoInst *ins = bb->code;       
13551                 int block_num = bb->block_num;
13552
13553                 if (cfg->verbose_level > 2)
13554                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13555
13556                 cfg->cbb = bb;
13557                 for (; ins; ins = ins->next) {
13558                         const char *spec = INS_INFO (ins->opcode);
13559                         int regtype = 0, regindex;
13560                         gint32 prev_bb;
13561
13562                         if (G_UNLIKELY (cfg->verbose_level > 2))
13563                                 mono_print_ins (ins);
13564
13565                         g_assert (ins->opcode >= MONO_CEE_LAST);
13566
13567                         for (regindex = 0; regindex < 4; regindex ++) {
13568                                 int vreg = 0;
13569
13570                                 if (regindex == 0) {
13571                                         regtype = spec [MONO_INST_DEST];
13572                                         if (regtype == ' ')
13573                                                 continue;
13574                                         vreg = ins->dreg;
13575                                 } else if (regindex == 1) {
13576                                         regtype = spec [MONO_INST_SRC1];
13577                                         if (regtype == ' ')
13578                                                 continue;
13579                                         vreg = ins->sreg1;
13580                                 } else if (regindex == 2) {
13581                                         regtype = spec [MONO_INST_SRC2];
13582                                         if (regtype == ' ')
13583                                                 continue;
13584                                         vreg = ins->sreg2;
13585                                 } else if (regindex == 3) {
13586                                         regtype = spec [MONO_INST_SRC3];
13587                                         if (regtype == ' ')
13588                                                 continue;
13589                                         vreg = ins->sreg3;
13590                                 }
13591
13592 #if SIZEOF_REGISTER == 4
13593                                 /* In the LLVM case, the long opcodes are not decomposed */
13594                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13595                                         /*
13596                                          * Since some instructions reference the original long vreg,
13597                                          * and some reference the two component vregs, it is quite hard
13598                                          * to determine when it needs to be global. So be conservative.
13599                                          */
13600                                         if (!get_vreg_to_inst (cfg, vreg)) {
13601                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13602
13603                                                 if (cfg->verbose_level > 2)
13604                                                         printf ("LONG VREG R%d made global.\n", vreg);
13605                                         }
13606
13607                                         /*
13608                                          * Make the component vregs volatile since the optimizations can
13609                                          * get confused otherwise.
13610                                          */
13611                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
13612                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
13613                                 }
13614 #endif
13615
13616                                 g_assert (vreg != -1);
13617
13618                                 prev_bb = vreg_to_bb [vreg];
13619                                 if (prev_bb == 0) {
13620                                         /* 0 is a valid block num */
13621                                         vreg_to_bb [vreg] = block_num + 1;
13622                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13623                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13624                                                 continue;
13625
13626                                         if (!get_vreg_to_inst (cfg, vreg)) {
13627                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13628                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13629
13630                                                 switch (regtype) {
13631                                                 case 'i':
13632                                                         if (vreg_is_ref (cfg, vreg))
13633                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13634                                                         else
13635                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13636                                                         break;
13637                                                 case 'l':
13638                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13639                                                         break;
13640                                                 case 'f':
13641                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13642                                                         break;
13643                                                 case 'v':
13644                                                 case 'x':
13645                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13646                                                         break;
13647                                                 default:
13648                                                         g_assert_not_reached ();
13649                                                 }
13650                                         }
13651
13652                                         /* Flag as having been used in more than one bb */
13653                                         vreg_to_bb [vreg] = -1;
13654                                 }
13655                         }
13656                 }
13657         }
13658
13659         /* If a variable is used in only one bblock, convert it into a local vreg */
13660         for (i = 0; i < cfg->num_varinfo; i++) {
13661                 MonoInst *var = cfg->varinfo [i];
13662                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13663
13664                 switch (var->type) {
13665                 case STACK_I4:
13666                 case STACK_OBJ:
13667                 case STACK_PTR:
13668                 case STACK_MP:
13669                 case STACK_VTYPE:
13670 #if SIZEOF_REGISTER == 8
13671                 case STACK_I8:
13672 #endif
13673 #if !defined(TARGET_X86)
13674                 /* Enabling this screws up the fp stack on x86 */
13675                 case STACK_R8:
13676 #endif
13677                         if (mono_arch_is_soft_float ())
13678                                 break;
13679
13680                         /*
13681                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
13682                                 break;
13683                         */
13684
13685                         /* Arguments are implicitly global */
13686                         /* Putting R4 vars into registers doesn't work currently */
13687                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13688                         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) {
13689                                 /* 
13690                                  * Make that the variable's liveness interval doesn't contain a call, since
13691                                  * that would cause the lvreg to be spilled, making the whole optimization
13692                                  * useless.
13693                                  */
13694                                 /* This is too slow for JIT compilation */
13695 #if 0
13696                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13697                                         MonoInst *ins;
13698                                         int def_index, call_index, ins_index;
13699                                         gboolean spilled = FALSE;
13700
13701                                         def_index = -1;
13702                                         call_index = -1;
13703                                         ins_index = 0;
13704                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13705                                                 const char *spec = INS_INFO (ins->opcode);
13706
13707                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13708                                                         def_index = ins_index;
13709
13710                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13711                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13712                                                         if (call_index > def_index) {
13713                                                                 spilled = TRUE;
13714                                                                 break;
13715                                                         }
13716                                                 }
13717
13718                                                 if (MONO_IS_CALL (ins))
13719                                                         call_index = ins_index;
13720
13721                                                 ins_index ++;
13722                                         }
13723
13724                                         if (spilled)
13725                                                 break;
13726                                 }
13727 #endif
13728
13729                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13730                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13731                                 var->flags |= MONO_INST_IS_DEAD;
13732                                 cfg->vreg_to_inst [var->dreg] = NULL;
13733                         }
13734                         break;
13735                 }
13736         }
13737
13738         /* 
13739          * Compress the varinfo and vars tables so the liveness computation is faster and
13740          * takes up less space.
13741          */
13742         pos = 0;
13743         for (i = 0; i < cfg->num_varinfo; ++i) {
13744                 MonoInst *var = cfg->varinfo [i];
13745                 if (pos < i && cfg->locals_start == i)
13746                         cfg->locals_start = pos;
13747                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13748                         if (pos < i) {
13749                                 cfg->varinfo [pos] = cfg->varinfo [i];
13750                                 cfg->varinfo [pos]->inst_c0 = pos;
13751                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13752                                 cfg->vars [pos].idx = pos;
13753 #if SIZEOF_REGISTER == 4
13754                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13755                                         /* Modify the two component vars too */
13756                                         MonoInst *var1;
13757
13758                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
13759                                         var1->inst_c0 = pos;
13760                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
13761                                         var1->inst_c0 = pos;
13762                                 }
13763 #endif
13764                         }
13765                         pos ++;
13766                 }
13767         }
13768         cfg->num_varinfo = pos;
13769         if (cfg->locals_start > cfg->num_varinfo)
13770                 cfg->locals_start = cfg->num_varinfo;
13771 }
13772
13773 /*
13774  * mono_allocate_gsharedvt_vars:
13775  *
13776  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
13777  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
13778  */
13779 void
13780 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
13781 {
13782         int i;
13783
13784         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13785
13786         for (i = 0; i < cfg->num_varinfo; ++i) {
13787                 MonoInst *ins = cfg->varinfo [i];
13788                 int idx;
13789
13790                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13791                         if (i >= cfg->locals_start) {
13792                                 /* Local */
13793                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13794                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13795                                 ins->opcode = OP_GSHAREDVT_LOCAL;
13796                                 ins->inst_imm = idx;
13797                         } else {
13798                                 /* Arg */
13799                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
13800                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13801                         }
13802                 }
13803         }
13804 }
13805
13806 /**
13807  * mono_spill_global_vars:
13808  *
13809  *   Generate spill code for variables which are not allocated to registers, 
13810  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13811  * code is generated which could be optimized by the local optimization passes.
13812  */
13813 void
13814 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13815 {
13816         MonoBasicBlock *bb;
13817         char spec2 [16];
13818         int orig_next_vreg;
13819         guint32 *vreg_to_lvreg;
13820         guint32 *lvregs;
13821         guint32 i, lvregs_len, lvregs_size;
13822         gboolean dest_has_lvreg = FALSE;
13823         MonoStackType stacktypes [128];
13824         MonoInst **live_range_start, **live_range_end;
13825         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13826
13827         *need_local_opts = FALSE;
13828
13829         memset (spec2, 0, sizeof (spec2));
13830
13831         /* FIXME: Move this function to mini.c */
13832         stacktypes ['i'] = STACK_PTR;
13833         stacktypes ['l'] = STACK_I8;
13834         stacktypes ['f'] = STACK_R8;
13835 #ifdef MONO_ARCH_SIMD_INTRINSICS
13836         stacktypes ['x'] = STACK_VTYPE;
13837 #endif
13838
13839 #if SIZEOF_REGISTER == 4
13840         /* Create MonoInsts for longs */
13841         for (i = 0; i < cfg->num_varinfo; i++) {
13842                 MonoInst *ins = cfg->varinfo [i];
13843
13844                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13845                         switch (ins->type) {
13846                         case STACK_R8:
13847                         case STACK_I8: {
13848                                 MonoInst *tree;
13849
13850                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13851                                         break;
13852
13853                                 g_assert (ins->opcode == OP_REGOFFSET);
13854
13855                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
13856                                 g_assert (tree);
13857                                 tree->opcode = OP_REGOFFSET;
13858                                 tree->inst_basereg = ins->inst_basereg;
13859                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13860
13861                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
13862                                 g_assert (tree);
13863                                 tree->opcode = OP_REGOFFSET;
13864                                 tree->inst_basereg = ins->inst_basereg;
13865                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13866                                 break;
13867                         }
13868                         default:
13869                                 break;
13870                         }
13871                 }
13872         }
13873 #endif
13874
13875         if (cfg->compute_gc_maps) {
13876                 /* registers need liveness info even for !non refs */
13877                 for (i = 0; i < cfg->num_varinfo; i++) {
13878                         MonoInst *ins = cfg->varinfo [i];
13879
13880                         if (ins->opcode == OP_REGVAR)
13881                                 ins->flags |= MONO_INST_GC_TRACK;
13882                 }
13883         }
13884                 
13885         /* FIXME: widening and truncation */
13886
13887         /*
13888          * As an optimization, when a variable allocated to the stack is first loaded into 
13889          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13890          * the variable again.
13891          */
13892         orig_next_vreg = cfg->next_vreg;
13893         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13894         lvregs_size = 1024;
13895         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * lvregs_size);
13896         lvregs_len = 0;
13897
13898         /* 
13899          * These arrays contain the first and last instructions accessing a given
13900          * variable.
13901          * Since we emit bblocks in the same order we process them here, and we
13902          * don't split live ranges, these will precisely describe the live range of
13903          * the variable, i.e. the instruction range where a valid value can be found
13904          * in the variables location.
13905          * The live range is computed using the liveness info computed by the liveness pass.
13906          * We can't use vmv->range, since that is an abstract live range, and we need
13907          * one which is instruction precise.
13908          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13909          */
13910         /* FIXME: Only do this if debugging info is requested */
13911         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13912         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13913         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13914         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13915         
13916         /* Add spill loads/stores */
13917         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13918                 MonoInst *ins;
13919
13920                 if (cfg->verbose_level > 2)
13921                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13922
13923                 /* Clear vreg_to_lvreg array */
13924                 for (i = 0; i < lvregs_len; i++)
13925                         vreg_to_lvreg [lvregs [i]] = 0;
13926                 lvregs_len = 0;
13927
13928                 cfg->cbb = bb;
13929                 MONO_BB_FOR_EACH_INS (bb, ins) {
13930                         const char *spec = INS_INFO (ins->opcode);
13931                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13932                         gboolean store, no_lvreg;
13933                         int sregs [MONO_MAX_SRC_REGS];
13934
13935                         if (G_UNLIKELY (cfg->verbose_level > 2))
13936                                 mono_print_ins (ins);
13937
13938                         if (ins->opcode == OP_NOP)
13939                                 continue;
13940
13941                         /* 
13942                          * We handle LDADDR here as well, since it can only be decomposed
13943                          * when variable addresses are known.
13944                          */
13945                         if (ins->opcode == OP_LDADDR) {
13946                                 MonoInst *var = (MonoInst *)ins->inst_p0;
13947
13948                                 if (var->opcode == OP_VTARG_ADDR) {
13949                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13950                                         MonoInst *vtaddr = var->inst_left;
13951                                         if (vtaddr->opcode == OP_REGVAR) {
13952                                                 ins->opcode = OP_MOVE;
13953                                                 ins->sreg1 = vtaddr->dreg;
13954                                         }
13955                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13956                                                 ins->opcode = OP_LOAD_MEMBASE;
13957                                                 ins->inst_basereg = vtaddr->inst_basereg;
13958                                                 ins->inst_offset = vtaddr->inst_offset;
13959                                         } else
13960                                                 NOT_IMPLEMENTED;
13961                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
13962                                         /* gsharedvt arg passed by ref */
13963                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13964
13965                                         ins->opcode = OP_LOAD_MEMBASE;
13966                                         ins->inst_basereg = var->inst_basereg;
13967                                         ins->inst_offset = var->inst_offset;
13968                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
13969                                         MonoInst *load, *load2, *load3;
13970                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
13971                                         int reg1, reg2, reg3;
13972                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13973                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13974
13975                                         /*
13976                                          * gsharedvt local.
13977                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13978                                          */
13979
13980                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13981
13982                                         g_assert (info_var);
13983                                         g_assert (locals_var);
13984
13985                                         /* Mark the instruction used to compute the locals var as used */
13986                                         cfg->gsharedvt_locals_var_ins = NULL;
13987
13988                                         /* Load the offset */
13989                                         if (info_var->opcode == OP_REGOFFSET) {
13990                                                 reg1 = alloc_ireg (cfg);
13991                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13992                                         } else if (info_var->opcode == OP_REGVAR) {
13993                                                 load = NULL;
13994                                                 reg1 = info_var->dreg;
13995                                         } else {
13996                                                 g_assert_not_reached ();
13997                                         }
13998                                         reg2 = alloc_ireg (cfg);
13999                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14000                                         /* Load the locals area address */
14001                                         reg3 = alloc_ireg (cfg);
14002                                         if (locals_var->opcode == OP_REGOFFSET) {
14003                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14004                                         } else if (locals_var->opcode == OP_REGVAR) {
14005                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14006                                         } else {
14007                                                 g_assert_not_reached ();
14008                                         }
14009                                         /* Compute the address */
14010                                         ins->opcode = OP_PADD;
14011                                         ins->sreg1 = reg3;
14012                                         ins->sreg2 = reg2;
14013
14014                                         mono_bblock_insert_before_ins (bb, ins, load3);
14015                                         mono_bblock_insert_before_ins (bb, load3, load2);
14016                                         if (load)
14017                                                 mono_bblock_insert_before_ins (bb, load2, load);
14018                                 } else {
14019                                         g_assert (var->opcode == OP_REGOFFSET);
14020
14021                                         ins->opcode = OP_ADD_IMM;
14022                                         ins->sreg1 = var->inst_basereg;
14023                                         ins->inst_imm = var->inst_offset;
14024                                 }
14025
14026                                 *need_local_opts = TRUE;
14027                                 spec = INS_INFO (ins->opcode);
14028                         }
14029
14030                         if (ins->opcode < MONO_CEE_LAST) {
14031                                 mono_print_ins (ins);
14032                                 g_assert_not_reached ();
14033                         }
14034
14035                         /*
14036                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14037                          * src register.
14038                          * FIXME:
14039                          */
14040                         if (MONO_IS_STORE_MEMBASE (ins)) {
14041                                 tmp_reg = ins->dreg;
14042                                 ins->dreg = ins->sreg2;
14043                                 ins->sreg2 = tmp_reg;
14044                                 store = TRUE;
14045
14046                                 spec2 [MONO_INST_DEST] = ' ';
14047                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14048                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14049                                 spec2 [MONO_INST_SRC3] = ' ';
14050                                 spec = spec2;
14051                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14052                                 g_assert_not_reached ();
14053                         else
14054                                 store = FALSE;
14055                         no_lvreg = FALSE;
14056
14057                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14058                                 printf ("\t %.3s %d", spec, ins->dreg);
14059                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14060                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14061                                         printf (" %d", sregs [srcindex]);
14062                                 printf ("\n");
14063                         }
14064
14065                         /***************/
14066                         /*    DREG     */
14067                         /***************/
14068                         regtype = spec [MONO_INST_DEST];
14069                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14070                         prev_dreg = -1;
14071
14072                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14073                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14074                                 MonoInst *store_ins;
14075                                 int store_opcode;
14076                                 MonoInst *def_ins = ins;
14077                                 int dreg = ins->dreg; /* The original vreg */
14078
14079                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14080
14081                                 if (var->opcode == OP_REGVAR) {
14082                                         ins->dreg = var->dreg;
14083                                 } 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)) {
14084                                         /* 
14085                                          * Instead of emitting a load+store, use a _membase opcode.
14086                                          */
14087                                         g_assert (var->opcode == OP_REGOFFSET);
14088                                         if (ins->opcode == OP_MOVE) {
14089                                                 NULLIFY_INS (ins);
14090                                                 def_ins = NULL;
14091                                         } else {
14092                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14093                                                 ins->inst_basereg = var->inst_basereg;
14094                                                 ins->inst_offset = var->inst_offset;
14095                                                 ins->dreg = -1;
14096                                         }
14097                                         spec = INS_INFO (ins->opcode);
14098                                 } else {
14099                                         guint32 lvreg;
14100
14101                                         g_assert (var->opcode == OP_REGOFFSET);
14102
14103                                         prev_dreg = ins->dreg;
14104
14105                                         /* Invalidate any previous lvreg for this vreg */
14106                                         vreg_to_lvreg [ins->dreg] = 0;
14107
14108                                         lvreg = 0;
14109
14110                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14111                                                 regtype = 'l';
14112                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14113                                         }
14114
14115                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14116
14117 #if SIZEOF_REGISTER != 8
14118                                         if (regtype == 'l') {
14119                                                 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));
14120                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14121                                                 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));
14122                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14123                                                 def_ins = store_ins;
14124                                         }
14125                                         else
14126 #endif
14127                                         {
14128                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14129
14130                                                 /* Try to fuse the store into the instruction itself */
14131                                                 /* FIXME: Add more instructions */
14132                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14133                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14134                                                         ins->inst_imm = ins->inst_c0;
14135                                                         ins->inst_destbasereg = var->inst_basereg;
14136                                                         ins->inst_offset = var->inst_offset;
14137                                                         spec = INS_INFO (ins->opcode);
14138                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14139                                                         ins->opcode = store_opcode;
14140                                                         ins->inst_destbasereg = var->inst_basereg;
14141                                                         ins->inst_offset = var->inst_offset;
14142
14143                                                         no_lvreg = TRUE;
14144
14145                                                         tmp_reg = ins->dreg;
14146                                                         ins->dreg = ins->sreg2;
14147                                                         ins->sreg2 = tmp_reg;
14148                                                         store = TRUE;
14149
14150                                                         spec2 [MONO_INST_DEST] = ' ';
14151                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14152                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14153                                                         spec2 [MONO_INST_SRC3] = ' ';
14154                                                         spec = spec2;
14155                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14156                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14157                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14158                                                         ins->dreg = -1;
14159                                                         ins->inst_basereg = var->inst_basereg;
14160                                                         ins->inst_offset = var->inst_offset;
14161                                                         spec = INS_INFO (ins->opcode);
14162                                                 } else {
14163                                                         /* printf ("INS: "); mono_print_ins (ins); */
14164                                                         /* Create a store instruction */
14165                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14166
14167                                                         /* Insert it after the instruction */
14168                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14169
14170                                                         def_ins = store_ins;
14171
14172                                                         /* 
14173                                                          * We can't assign ins->dreg to var->dreg here, since the
14174                                                          * sregs could use it. So set a flag, and do it after
14175                                                          * the sregs.
14176                                                          */
14177                                                         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)))
14178                                                                 dest_has_lvreg = TRUE;
14179                                                 }
14180                                         }
14181                                 }
14182
14183                                 if (def_ins && !live_range_start [dreg]) {
14184                                         live_range_start [dreg] = def_ins;
14185                                         live_range_start_bb [dreg] = bb;
14186                                 }
14187
14188                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14189                                         MonoInst *tmp;
14190
14191                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14192                                         tmp->inst_c1 = dreg;
14193                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14194                                 }
14195                         }
14196
14197                         /************/
14198                         /*  SREGS   */
14199                         /************/
14200                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14201                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14202                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14203                                 sreg = sregs [srcindex];
14204
14205                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14206                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14207                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14208                                         MonoInst *use_ins = ins;
14209                                         MonoInst *load_ins;
14210                                         guint32 load_opcode;
14211
14212                                         if (var->opcode == OP_REGVAR) {
14213                                                 sregs [srcindex] = var->dreg;
14214                                                 //mono_inst_set_src_registers (ins, sregs);
14215                                                 live_range_end [sreg] = use_ins;
14216                                                 live_range_end_bb [sreg] = bb;
14217
14218                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14219                                                         MonoInst *tmp;
14220
14221                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14222                                                         /* var->dreg is a hreg */
14223                                                         tmp->inst_c1 = sreg;
14224                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14225                                                 }
14226
14227                                                 continue;
14228                                         }
14229
14230                                         g_assert (var->opcode == OP_REGOFFSET);
14231                                                 
14232                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14233
14234                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14235
14236                                         if (vreg_to_lvreg [sreg]) {
14237                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14238
14239                                                 /* The variable is already loaded to an lvreg */
14240                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14241                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14242                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14243                                                 //mono_inst_set_src_registers (ins, sregs);
14244                                                 continue;
14245                                         }
14246
14247                                         /* Try to fuse the load into the instruction */
14248                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14249                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14250                                                 sregs [0] = var->inst_basereg;
14251                                                 //mono_inst_set_src_registers (ins, sregs);
14252                                                 ins->inst_offset = var->inst_offset;
14253                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14254                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14255                                                 sregs [1] = var->inst_basereg;
14256                                                 //mono_inst_set_src_registers (ins, sregs);
14257                                                 ins->inst_offset = var->inst_offset;
14258                                         } else {
14259                                                 if (MONO_IS_REAL_MOVE (ins)) {
14260                                                         ins->opcode = OP_NOP;
14261                                                         sreg = ins->dreg;
14262                                                 } else {
14263                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14264
14265                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14266
14267                                                         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) {
14268                                                                 if (var->dreg == prev_dreg) {
14269                                                                         /*
14270                                                                          * sreg refers to the value loaded by the load
14271                                                                          * emitted below, but we need to use ins->dreg
14272                                                                          * since it refers to the store emitted earlier.
14273                                                                          */
14274                                                                         sreg = ins->dreg;
14275                                                                 }
14276                                                                 g_assert (sreg != -1);
14277                                                                 vreg_to_lvreg [var->dreg] = sreg;
14278                                                                 if (lvregs_len >= lvregs_size) {
14279                                                                         guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
14280                                                                         memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
14281                                                                         lvregs = new_lvregs;
14282                                                                         lvregs_size *= 2;
14283                                                                 }
14284                                                                 lvregs [lvregs_len ++] = var->dreg;
14285                                                         }
14286                                                 }
14287
14288                                                 sregs [srcindex] = sreg;
14289                                                 //mono_inst_set_src_registers (ins, sregs);
14290
14291 #if SIZEOF_REGISTER != 8
14292                                                 if (regtype == 'l') {
14293                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14294                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14295                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14296                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14297                                                         use_ins = load_ins;
14298                                                 }
14299                                                 else
14300 #endif
14301                                                 {
14302 #if SIZEOF_REGISTER == 4
14303                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14304 #endif
14305                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14306                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14307                                                         use_ins = load_ins;
14308                                                 }
14309                                         }
14310
14311                                         if (var->dreg < orig_next_vreg) {
14312                                                 live_range_end [var->dreg] = use_ins;
14313                                                 live_range_end_bb [var->dreg] = bb;
14314                                         }
14315
14316                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14317                                                 MonoInst *tmp;
14318
14319                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14320                                                 tmp->inst_c1 = var->dreg;
14321                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14322                                         }
14323                                 }
14324                         }
14325                         mono_inst_set_src_registers (ins, sregs);
14326
14327                         if (dest_has_lvreg) {
14328                                 g_assert (ins->dreg != -1);
14329                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14330                                 if (lvregs_len >= lvregs_size) {
14331                                         guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
14332                                         memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
14333                                         lvregs = new_lvregs;
14334                                         lvregs_size *= 2;
14335                                 }
14336                                 lvregs [lvregs_len ++] = prev_dreg;
14337                                 dest_has_lvreg = FALSE;
14338                         }
14339
14340                         if (store) {
14341                                 tmp_reg = ins->dreg;
14342                                 ins->dreg = ins->sreg2;
14343                                 ins->sreg2 = tmp_reg;
14344                         }
14345
14346                         if (MONO_IS_CALL (ins)) {
14347                                 /* Clear vreg_to_lvreg array */
14348                                 for (i = 0; i < lvregs_len; i++)
14349                                         vreg_to_lvreg [lvregs [i]] = 0;
14350                                 lvregs_len = 0;
14351                         } else if (ins->opcode == OP_NOP) {
14352                                 ins->dreg = -1;
14353                                 MONO_INST_NULLIFY_SREGS (ins);
14354                         }
14355
14356                         if (cfg->verbose_level > 2)
14357                                 mono_print_ins_index (1, ins);
14358                 }
14359
14360                 /* Extend the live range based on the liveness info */
14361                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14362                         for (i = 0; i < cfg->num_varinfo; i ++) {
14363                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14364
14365                                 if (vreg_is_volatile (cfg, vi->vreg))
14366                                         /* The liveness info is incomplete */
14367                                         continue;
14368
14369                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14370                                         /* Live from at least the first ins of this bb */
14371                                         live_range_start [vi->vreg] = bb->code;
14372                                         live_range_start_bb [vi->vreg] = bb;
14373                                 }
14374
14375                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14376                                         /* Live at least until the last ins of this bb */
14377                                         live_range_end [vi->vreg] = bb->last_ins;
14378                                         live_range_end_bb [vi->vreg] = bb;
14379                                 }
14380                         }
14381                 }
14382         }
14383         
14384         /*
14385          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14386          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14387          */
14388         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14389                 for (i = 0; i < cfg->num_varinfo; ++i) {
14390                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14391                         MonoInst *ins;
14392
14393                         if (live_range_start [vreg]) {
14394                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14395                                 ins->inst_c0 = i;
14396                                 ins->inst_c1 = vreg;
14397                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14398                         }
14399                         if (live_range_end [vreg]) {
14400                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14401                                 ins->inst_c0 = i;
14402                                 ins->inst_c1 = vreg;
14403                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14404                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14405                                 else
14406                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14407                         }
14408                 }
14409         }
14410
14411         if (cfg->gsharedvt_locals_var_ins) {
14412                 /* Nullify if unused */
14413                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14414                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14415         }
14416
14417         g_free (live_range_start);
14418         g_free (live_range_end);
14419         g_free (live_range_start_bb);
14420         g_free (live_range_end_bb);
14421 }
14422
14423
14424 /**
14425  * FIXME:
14426  * - use 'iadd' instead of 'int_add'
14427  * - handling ovf opcodes: decompose in method_to_ir.
14428  * - unify iregs/fregs
14429  *   -> partly done, the missing parts are:
14430  *   - a more complete unification would involve unifying the hregs as well, so
14431  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14432  *     would no longer map to the machine hregs, so the code generators would need to
14433  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14434  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14435  *     fp/non-fp branches speeds it up by about 15%.
14436  * - use sext/zext opcodes instead of shifts
14437  * - add OP_ICALL
14438  * - get rid of TEMPLOADs if possible and use vregs instead
14439  * - clean up usage of OP_P/OP_ opcodes
14440  * - cleanup usage of DUMMY_USE
14441  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14442  *   stack
14443  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14444  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14445  * - make sure handle_stack_args () is called before the branch is emitted
14446  * - when the new IR is done, get rid of all unused stuff
14447  * - COMPARE/BEQ as separate instructions or unify them ?
14448  *   - keeping them separate allows specialized compare instructions like
14449  *     compare_imm, compare_membase
14450  *   - most back ends unify fp compare+branch, fp compare+ceq
14451  * - integrate mono_save_args into inline_method
14452  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14453  * - handle long shift opts on 32 bit platforms somehow: they require 
14454  *   3 sregs (2 for arg1 and 1 for arg2)
14455  * - make byref a 'normal' type.
14456  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14457  *   variable if needed.
14458  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14459  *   like inline_method.
14460  * - remove inlining restrictions
14461  * - fix LNEG and enable cfold of INEG
14462  * - generalize x86 optimizations like ldelema as a peephole optimization
14463  * - add store_mem_imm for amd64
14464  * - optimize the loading of the interruption flag in the managed->native wrappers
14465  * - avoid special handling of OP_NOP in passes
14466  * - move code inserting instructions into one function/macro.
14467  * - try a coalescing phase after liveness analysis
14468  * - add float -> vreg conversion + local optimizations on !x86
14469  * - figure out how to handle decomposed branches during optimizations, ie.
14470  *   compare+branch, op_jump_table+op_br etc.
14471  * - promote RuntimeXHandles to vregs
14472  * - vtype cleanups:
14473  *   - add a NEW_VARLOADA_VREG macro
14474  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14475  *   accessing vtype fields.
14476  * - get rid of I8CONST on 64 bit platforms
14477  * - dealing with the increase in code size due to branches created during opcode
14478  *   decomposition:
14479  *   - use extended basic blocks
14480  *     - all parts of the JIT
14481  *     - handle_global_vregs () && local regalloc
14482  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14483  * - sources of increase in code size:
14484  *   - vtypes
14485  *   - long compares
14486  *   - isinst and castclass
14487  *   - lvregs not allocated to global registers even if used multiple times
14488  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14489  *   meaningful.
14490  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14491  * - add all micro optimizations from the old JIT
14492  * - put tree optimizations into the deadce pass
14493  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14494  *   specific function.
14495  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14496  *   fcompare + branchCC.
14497  * - create a helper function for allocating a stack slot, taking into account 
14498  *   MONO_CFG_HAS_SPILLUP.
14499  * - merge r68207.
14500  * - merge the ia64 switch changes.
14501  * - optimize mono_regstate2_alloc_int/float.
14502  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14503  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14504  *   parts of the tree could be separated by other instructions, killing the tree
14505  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14506  *   instructions if the result of the load is used multiple times ?
14507  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14508  * - LAST MERGE: 108395.
14509  * - when returning vtypes in registers, generate IR and append it to the end of the
14510  *   last bb instead of doing it in the epilog.
14511  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14512  */
14513
14514 /*
14515
14516 NOTES
14517 -----
14518
14519 - When to decompose opcodes:
14520   - earlier: this makes some optimizations hard to implement, since the low level IR
14521   no longer contains the neccessary information. But it is easier to do.
14522   - later: harder to implement, enables more optimizations.
14523 - Branches inside bblocks:
14524   - created when decomposing complex opcodes. 
14525     - branches to another bblock: harmless, but not tracked by the branch 
14526       optimizations, so need to branch to a label at the start of the bblock.
14527     - branches to inside the same bblock: very problematic, trips up the local
14528       reg allocator. Can be fixed by spitting the current bblock, but that is a
14529       complex operation, since some local vregs can become global vregs etc.
14530 - Local/global vregs:
14531   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14532     local register allocator.
14533   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14534     structure, created by mono_create_var (). Assigned to hregs or the stack by
14535     the global register allocator.
14536 - When to do optimizations like alu->alu_imm:
14537   - earlier -> saves work later on since the IR will be smaller/simpler
14538   - later -> can work on more instructions
14539 - Handling of valuetypes:
14540   - When a vtype is pushed on the stack, a new temporary is created, an 
14541     instruction computing its address (LDADDR) is emitted and pushed on
14542     the stack. Need to optimize cases when the vtype is used immediately as in
14543     argument passing, stloc etc.
14544 - Instead of the to_end stuff in the old JIT, simply call the function handling
14545   the values on the stack before emitting the last instruction of the bb.
14546 */
14547
14548 #else /* !DISABLE_JIT */
14549
14550 MONO_EMPTY_SOURCE_FILE (method_to_ir);
14551
14552 #endif /* !DISABLE_JIT */