[jit] Implement RuntimeHelpers.IsReferenceOrContainsReferences intrinsic. Fixes ...
[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 #include "mini.h"
17
18 #ifndef DISABLE_JIT
19
20 #include <signal.h>
21
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25
26 #include <math.h>
27 #include <string.h>
28 #include <ctype.h>
29
30 #ifdef HAVE_SYS_TIME_H
31 #include <sys/time.h>
32 #endif
33
34 #ifdef HAVE_ALLOCA_H
35 #include <alloca.h>
36 #endif
37
38 #include <mono/utils/memcheck.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 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
146                                                   guchar *ip, guint real_offset, gboolean inline_always);
147 static MonoInst*
148 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
149
150 inline static MonoInst*
151 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg);
152
153 /* helper methods signatures */
154 static MonoMethodSignature *helper_sig_domain_get;
155 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
156 static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline;
157 static MonoMethodSignature *helper_sig_jit_thread_attach;
158 static MonoMethodSignature *helper_sig_get_tls_tramp;
159 static MonoMethodSignature *helper_sig_set_tls_tramp;
160
161 /* type loading helpers */
162 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, "System.Runtime.CompilerServices", "RuntimeHelpers")
163 static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, "System.Diagnostics", "DebuggableAttribute")
164
165 /*
166  * Instruction metadata
167  */
168 #ifdef MINI_OP
169 #undef MINI_OP
170 #endif
171 #ifdef MINI_OP3
172 #undef MINI_OP3
173 #endif
174 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
175 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
176 #define NONE ' '
177 #define IREG 'i'
178 #define FREG 'f'
179 #define VREG 'v'
180 #define XREG 'x'
181 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
182 #define LREG IREG
183 #else
184 #define LREG 'l'
185 #endif
186 /* keep in sync with the enum in mini.h */
187 const char
188 ins_info[] = {
189 #include "mini-ops.h"
190 };
191 #undef MINI_OP
192 #undef MINI_OP3
193
194 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
195 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
196 /* 
197  * This should contain the index of the last sreg + 1. This is not the same
198  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
199  */
200 const gint8 ins_sreg_counts[] = {
201 #include "mini-ops.h"
202 };
203 #undef MINI_OP
204 #undef MINI_OP3
205
206 guint32
207 mono_alloc_ireg (MonoCompile *cfg)
208 {
209         return alloc_ireg (cfg);
210 }
211
212 guint32
213 mono_alloc_lreg (MonoCompile *cfg)
214 {
215         return alloc_lreg (cfg);
216 }
217
218 guint32
219 mono_alloc_freg (MonoCompile *cfg)
220 {
221         return alloc_freg (cfg);
222 }
223
224 guint32
225 mono_alloc_preg (MonoCompile *cfg)
226 {
227         return alloc_preg (cfg);
228 }
229
230 guint32
231 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
232 {
233         return alloc_dreg (cfg, stack_type);
234 }
235
236 /*
237  * mono_alloc_ireg_ref:
238  *
239  *   Allocate an IREG, and mark it as holding a GC ref.
240  */
241 guint32
242 mono_alloc_ireg_ref (MonoCompile *cfg)
243 {
244         return alloc_ireg_ref (cfg);
245 }
246
247 /*
248  * mono_alloc_ireg_mp:
249  *
250  *   Allocate an IREG, and mark it as holding a managed pointer.
251  */
252 guint32
253 mono_alloc_ireg_mp (MonoCompile *cfg)
254 {
255         return alloc_ireg_mp (cfg);
256 }
257
258 /*
259  * mono_alloc_ireg_copy:
260  *
261  *   Allocate an IREG with the same GC type as VREG.
262  */
263 guint32
264 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
265 {
266         if (vreg_is_ref (cfg, vreg))
267                 return alloc_ireg_ref (cfg);
268         else if (vreg_is_mp (cfg, vreg))
269                 return alloc_ireg_mp (cfg);
270         else
271                 return alloc_ireg (cfg);
272 }
273
274 guint
275 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
276 {
277         if (type->byref)
278                 return OP_MOVE;
279
280         type = mini_get_underlying_type (type);
281 handle_enum:
282         switch (type->type) {
283         case MONO_TYPE_I1:
284         case MONO_TYPE_U1:
285                 return OP_MOVE;
286         case MONO_TYPE_I2:
287         case MONO_TYPE_U2:
288                 return OP_MOVE;
289         case MONO_TYPE_I4:
290         case MONO_TYPE_U4:
291                 return OP_MOVE;
292         case MONO_TYPE_I:
293         case MONO_TYPE_U:
294         case MONO_TYPE_PTR:
295         case MONO_TYPE_FNPTR:
296                 return OP_MOVE;
297         case MONO_TYPE_CLASS:
298         case MONO_TYPE_STRING:
299         case MONO_TYPE_OBJECT:
300         case MONO_TYPE_SZARRAY:
301         case MONO_TYPE_ARRAY:    
302                 return OP_MOVE;
303         case MONO_TYPE_I8:
304         case MONO_TYPE_U8:
305 #if SIZEOF_REGISTER == 8
306                 return OP_MOVE;
307 #else
308                 return OP_LMOVE;
309 #endif
310         case MONO_TYPE_R4:
311                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
312         case MONO_TYPE_R8:
313                 return OP_FMOVE;
314         case MONO_TYPE_VALUETYPE:
315                 if (type->data.klass->enumtype) {
316                         type = mono_class_enum_basetype (type->data.klass);
317                         goto handle_enum;
318                 }
319                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
320                         return OP_XMOVE;
321                 return OP_VMOVE;
322         case MONO_TYPE_TYPEDBYREF:
323                 return OP_VMOVE;
324         case MONO_TYPE_GENERICINST:
325                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
326                         return OP_XMOVE;
327                 type = &type->data.generic_class->container_class->byval_arg;
328                 goto handle_enum;
329         case MONO_TYPE_VAR:
330         case MONO_TYPE_MVAR:
331                 g_assert (cfg->gshared);
332                 if (mini_type_var_is_vt (type))
333                         return OP_VMOVE;
334                 else
335                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
336         default:
337                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
338         }
339         return -1;
340 }
341
342 void
343 mono_print_bb (MonoBasicBlock *bb, const char *msg)
344 {
345         int i;
346         MonoInst *tree;
347         GString *str = g_string_new ("");
348
349         g_string_append_printf (str, "%s %d: [IN: ", msg, bb->block_num);
350         for (i = 0; i < bb->in_count; ++i)
351                 g_string_append_printf (str, " BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
352         g_string_append_printf (str, ", OUT: ");
353         for (i = 0; i < bb->out_count; ++i)
354                 g_string_append_printf (str, " BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
355         g_string_append_printf (str, " ]\n");
356
357         g_print ("%s", str->str);
358         g_string_free (str, TRUE);
359
360         for (tree = bb->code; tree; tree = tree->next)
361                 mono_print_ins_index (-1, tree);
362 }
363
364 void
365 mono_create_helper_signatures (void)
366 {
367         helper_sig_domain_get = mono_create_icall_signature ("ptr");
368         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
369         helper_sig_llvmonly_imt_trampoline = mono_create_icall_signature ("ptr ptr ptr");
370         helper_sig_jit_thread_attach = mono_create_icall_signature ("ptr ptr");
371         helper_sig_get_tls_tramp = mono_create_icall_signature ("ptr");
372         helper_sig_set_tls_tramp = mono_create_icall_signature ("void ptr");
373 }
374
375 static MONO_NEVER_INLINE void
376 break_on_unverified (void)
377 {
378         if (mini_get_debug_options ()->break_on_unverified)
379                 G_BREAKPOINT ();
380 }
381
382 static MONO_NEVER_INLINE void
383 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
384 {
385         char *method_fname = mono_method_full_name (method, TRUE);
386         char *field_fname = mono_field_full_name (field);
387         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
388         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
389         g_free (method_fname);
390         g_free (field_fname);
391 }
392
393 static MONO_NEVER_INLINE void
394 inline_failure (MonoCompile *cfg, const char *msg)
395 {
396         if (cfg->verbose_level >= 2)
397                 printf ("inline failed: %s\n", msg);
398         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
399 }
400
401 static MONO_NEVER_INLINE void
402 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
403 {
404         if (cfg->verbose_level > 2)                                                                                     \
405                 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);
406         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
407 }
408
409 static MONO_NEVER_INLINE void
410 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
411 {
412         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);
413         if (cfg->verbose_level >= 2)
414                 printf ("%s\n", cfg->exception_message);
415         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
416 }
417
418 /*
419  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
420  * foo<T> (int i) { ldarg.0; box T; }
421  */
422 #define UNVERIFIED do { \
423         if (cfg->gsharedvt) { \
424                 if (cfg->verbose_level > 2)                                                                     \
425                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
426                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
427                 goto exception_exit;                                                                                    \
428         }                                                                                                                                       \
429         break_on_unverified ();                                                                                         \
430         goto unverified;                                                                                                        \
431 } while (0)
432
433 #define GET_BBLOCK(cfg,tblock,ip) do {  \
434                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
435                 if (!(tblock)) {        \
436                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
437             NEW_BBLOCK (cfg, (tblock)); \
438                         (tblock)->cil_code = (ip);      \
439                         ADD_BBLOCK (cfg, (tblock));     \
440                 } \
441         } while (0)
442
443 #if defined(TARGET_X86) || defined(TARGET_AMD64)
444 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
445                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
446                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
447                 (dest)->sreg1 = (sr1); \
448                 (dest)->sreg2 = (sr2); \
449                 (dest)->inst_imm = (imm); \
450                 (dest)->backend.shift_amount = (shift); \
451                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
452         } while (0)
453 #endif
454
455 /* Emit conversions so both operands of a binary opcode are of the same type */
456 static void
457 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
458 {
459         MonoInst *arg1 = *arg1_ref;
460         MonoInst *arg2 = *arg2_ref;
461
462         if (cfg->r4fp &&
463                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
464                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
465                 MonoInst *conv;
466
467                 /* Mixing r4/r8 is allowed by the spec */
468                 if (arg1->type == STACK_R4) {
469                         int dreg = alloc_freg (cfg);
470
471                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
472                         conv->type = STACK_R8;
473                         ins->sreg1 = dreg;
474                         *arg1_ref = conv;
475                 }
476                 if (arg2->type == STACK_R4) {
477                         int dreg = alloc_freg (cfg);
478
479                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
480                         conv->type = STACK_R8;
481                         ins->sreg2 = dreg;
482                         *arg2_ref = conv;
483                 }
484         }
485
486 #if SIZEOF_REGISTER == 8
487         /* FIXME: Need to add many more cases */
488         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
489                 MonoInst *widen;
490
491                 int dr = alloc_preg (cfg);
492                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
493                 (ins)->sreg2 = widen->dreg;
494         }
495 #endif
496 }
497
498 #define ADD_BINOP(op) do {      \
499                 MONO_INST_NEW (cfg, ins, (op)); \
500                 sp -= 2;        \
501                 ins->sreg1 = sp [0]->dreg;      \
502                 ins->sreg2 = sp [1]->dreg;      \
503                 type_from_op (cfg, ins, sp [0], sp [1]);        \
504                 CHECK_TYPE (ins);       \
505                 /* Have to insert a widening op */               \
506         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
507         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
508         MONO_ADD_INS ((cfg)->cbb, (ins)); \
509         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
510         } while (0)
511
512 #define ADD_UNOP(op) do {       \
513                 MONO_INST_NEW (cfg, ins, (op)); \
514                 sp--;   \
515                 ins->sreg1 = sp [0]->dreg;      \
516                 type_from_op (cfg, ins, sp [0], NULL);  \
517                 CHECK_TYPE (ins);       \
518         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
519         MONO_ADD_INS ((cfg)->cbb, (ins)); \
520                 *sp++ = mono_decompose_opcode (cfg, ins);       \
521         } while (0)
522
523 #define ADD_BINCOND(next_block) do {    \
524                 MonoInst *cmp;  \
525                 sp -= 2; \
526                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
527                 cmp->sreg1 = sp [0]->dreg;      \
528                 cmp->sreg2 = sp [1]->dreg;      \
529                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
530                 CHECK_TYPE (cmp);       \
531                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
532                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
533                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
534                 GET_BBLOCK (cfg, tblock, target);               \
535                 link_bblock (cfg, cfg->cbb, tblock);    \
536                 ins->inst_true_bb = tblock;     \
537                 if ((next_block)) {     \
538                         link_bblock (cfg, cfg->cbb, (next_block));      \
539                         ins->inst_false_bb = (next_block);      \
540                         start_new_bblock = 1;   \
541                 } else {        \
542                         GET_BBLOCK (cfg, tblock, ip);           \
543                         link_bblock (cfg, cfg->cbb, tblock);    \
544                         ins->inst_false_bb = tblock;    \
545                         start_new_bblock = 2;   \
546                 }       \
547                 if (sp != stack_start) {                                                                        \
548                     handle_stack_args (cfg, stack_start, sp - stack_start); \
549                         CHECK_UNVERIFIABLE (cfg); \
550                 } \
551         MONO_ADD_INS (cfg->cbb, cmp); \
552                 MONO_ADD_INS (cfg->cbb, ins);   \
553         } while (0)
554
555 /* *
556  * link_bblock: Links two basic blocks
557  *
558  * links two basic blocks in the control flow graph, the 'from'
559  * argument is the starting block and the 'to' argument is the block
560  * the control flow ends to after 'from'.
561  */
562 static void
563 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
564 {
565         MonoBasicBlock **newa;
566         int i, found;
567
568 #if 0
569         if (from->cil_code) {
570                 if (to->cil_code)
571                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
572                 else
573                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
574         } else {
575                 if (to->cil_code)
576                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
577                 else
578                         printf ("edge from entry to exit\n");
579         }
580 #endif
581
582         found = FALSE;
583         for (i = 0; i < from->out_count; ++i) {
584                 if (to == from->out_bb [i]) {
585                         found = TRUE;
586                         break;
587                 }
588         }
589         if (!found) {
590                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
591                 for (i = 0; i < from->out_count; ++i) {
592                         newa [i] = from->out_bb [i];
593                 }
594                 newa [i] = to;
595                 from->out_count++;
596                 from->out_bb = newa;
597         }
598
599         found = FALSE;
600         for (i = 0; i < to->in_count; ++i) {
601                 if (from == to->in_bb [i]) {
602                         found = TRUE;
603                         break;
604                 }
605         }
606         if (!found) {
607                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
608                 for (i = 0; i < to->in_count; ++i) {
609                         newa [i] = to->in_bb [i];
610                 }
611                 newa [i] = from;
612                 to->in_count++;
613                 to->in_bb = newa;
614         }
615 }
616
617 void
618 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
619 {
620         link_bblock (cfg, from, to);
621 }
622
623 /**
624  * mono_find_block_region:
625  *
626  *   We mark each basic block with a region ID. We use that to avoid BB
627  *   optimizations when blocks are in different regions.
628  *
629  * Returns:
630  *   A region token that encodes where this region is, and information
631  *   about the clause owner for this block.
632  *
633  *   The region encodes the try/catch/filter clause that owns this block
634  *   as well as the type.  -1 is a special value that represents a block
635  *   that is in none of try/catch/filter.
636  */
637 static int
638 mono_find_block_region (MonoCompile *cfg, int offset)
639 {
640         MonoMethodHeader *header = cfg->header;
641         MonoExceptionClause *clause;
642         int i;
643
644         for (i = 0; i < header->num_clauses; ++i) {
645                 clause = &header->clauses [i];
646                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
647                     (offset < (clause->handler_offset)))
648                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
649                            
650                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
651                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
652                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
653                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
654                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
655                         else
656                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
657                 }
658         }
659         for (i = 0; i < header->num_clauses; ++i) {
660                 clause = &header->clauses [i];
661
662                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
663                         return ((i + 1) << 8) | clause->flags;
664         }
665
666         return -1;
667 }
668
669 static gboolean
670 ip_in_finally_clause (MonoCompile *cfg, int offset)
671 {
672         MonoMethodHeader *header = cfg->header;
673         MonoExceptionClause *clause;
674         int i;
675
676         for (i = 0; i < header->num_clauses; ++i) {
677                 clause = &header->clauses [i];
678                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
679                         continue;
680
681                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
682                         return TRUE;
683         }
684         return FALSE;
685 }
686
687 static GList*
688 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
689 {
690         MonoMethodHeader *header = cfg->header;
691         MonoExceptionClause *clause;
692         int i;
693         GList *res = NULL;
694
695         for (i = 0; i < header->num_clauses; ++i) {
696                 clause = &header->clauses [i];
697                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
698                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
699                         if (clause->flags == type)
700                                 res = g_list_append (res, clause);
701                 }
702         }
703         return res;
704 }
705
706 static void
707 mono_create_spvar_for_region (MonoCompile *cfg, int region)
708 {
709         MonoInst *var;
710
711         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
712         if (var)
713                 return;
714
715         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
716         /* prevent it from being register allocated */
717         var->flags |= MONO_INST_VOLATILE;
718
719         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
720 }
721
722 MonoInst *
723 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
724 {
725         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
726 }
727
728 static MonoInst*
729 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
730 {
731         MonoInst *var;
732
733         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
734         if (var)
735                 return var;
736
737         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
738         /* prevent it from being register allocated */
739         var->flags |= MONO_INST_VOLATILE;
740
741         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
742
743         return var;
744 }
745
746 /*
747  * Returns the type used in the eval stack when @type is loaded.
748  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
749  */
750 void
751 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
752 {
753         MonoClass *klass;
754
755         type = mini_get_underlying_type (type);
756         inst->klass = klass = mono_class_from_mono_type (type);
757         if (type->byref) {
758                 inst->type = STACK_MP;
759                 return;
760         }
761
762 handle_enum:
763         switch (type->type) {
764         case MONO_TYPE_VOID:
765                 inst->type = STACK_INV;
766                 return;
767         case MONO_TYPE_I1:
768         case MONO_TYPE_U1:
769         case MONO_TYPE_I2:
770         case MONO_TYPE_U2:
771         case MONO_TYPE_I4:
772         case MONO_TYPE_U4:
773                 inst->type = STACK_I4;
774                 return;
775         case MONO_TYPE_I:
776         case MONO_TYPE_U:
777         case MONO_TYPE_PTR:
778         case MONO_TYPE_FNPTR:
779                 inst->type = STACK_PTR;
780                 return;
781         case MONO_TYPE_CLASS:
782         case MONO_TYPE_STRING:
783         case MONO_TYPE_OBJECT:
784         case MONO_TYPE_SZARRAY:
785         case MONO_TYPE_ARRAY:    
786                 inst->type = STACK_OBJ;
787                 return;
788         case MONO_TYPE_I8:
789         case MONO_TYPE_U8:
790                 inst->type = STACK_I8;
791                 return;
792         case MONO_TYPE_R4:
793                 inst->type = cfg->r4_stack_type;
794                 break;
795         case MONO_TYPE_R8:
796                 inst->type = STACK_R8;
797                 return;
798         case MONO_TYPE_VALUETYPE:
799                 if (type->data.klass->enumtype) {
800                         type = mono_class_enum_basetype (type->data.klass);
801                         goto handle_enum;
802                 } else {
803                         inst->klass = klass;
804                         inst->type = STACK_VTYPE;
805                         return;
806                 }
807         case MONO_TYPE_TYPEDBYREF:
808                 inst->klass = mono_defaults.typed_reference_class;
809                 inst->type = STACK_VTYPE;
810                 return;
811         case MONO_TYPE_GENERICINST:
812                 type = &type->data.generic_class->container_class->byval_arg;
813                 goto handle_enum;
814         case MONO_TYPE_VAR:
815         case MONO_TYPE_MVAR:
816                 g_assert (cfg->gshared);
817                 if (mini_is_gsharedvt_type (type)) {
818                         g_assert (cfg->gsharedvt);
819                         inst->type = STACK_VTYPE;
820                 } else {
821                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
822                 }
823                 return;
824         default:
825                 g_error ("unknown type 0x%02x in eval stack type", type->type);
826         }
827 }
828
829 /*
830  * The following tables are used to quickly validate the IL code in type_from_op ().
831  */
832 static const char
833 bin_num_table [STACK_MAX] [STACK_MAX] = {
834         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
835         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
836         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
837         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
838         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
839         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
840         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
841         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
842         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
843 };
844
845 static const char 
846 neg_table [] = {
847         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
848 };
849
850 /* reduce the size of this table */
851 static const char
852 bin_int_table [STACK_MAX] [STACK_MAX] = {
853         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
854         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
855         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
856         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
857         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
858         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
859         {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 };
862
863 static const char
864 bin_comp_table [STACK_MAX] [STACK_MAX] = {
865 /*      Inv i  L  p  F  &  O  vt r4 */
866         {0},
867         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
868         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
869         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
870         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
871         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
872         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
873         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
874         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
875 };
876
877 /* reduce the size of this table */
878 static const char
879 shift_table [STACK_MAX] [STACK_MAX] = {
880         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
881         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
882         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
883         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
884         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
885         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
886         {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 };
889
890 /*
891  * Tables to map from the non-specific opcode to the matching
892  * type-specific opcode.
893  */
894 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
895 static const guint16
896 binops_op_map [STACK_MAX] = {
897         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
898 };
899
900 /* handles from CEE_NEG to CEE_CONV_U8 */
901 static const guint16
902 unops_op_map [STACK_MAX] = {
903         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
904 };
905
906 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
907 static const guint16
908 ovfops_op_map [STACK_MAX] = {
909         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
910 };
911
912 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
913 static const guint16
914 ovf2ops_op_map [STACK_MAX] = {
915         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
916 };
917
918 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
919 static const guint16
920 ovf3ops_op_map [STACK_MAX] = {
921         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
922 };
923
924 /* handles from CEE_BEQ to CEE_BLT_UN */
925 static const guint16
926 beqops_op_map [STACK_MAX] = {
927         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
928 };
929
930 /* handles from CEE_CEQ to CEE_CLT_UN */
931 static const guint16
932 ceqops_op_map [STACK_MAX] = {
933         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
934 };
935
936 /*
937  * Sets ins->type (the type on the eval stack) according to the
938  * type of the opcode and the arguments to it.
939  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
940  *
941  * FIXME: this function sets ins->type unconditionally in some cases, but
942  * it should set it to invalid for some types (a conv.x on an object)
943  */
944 static void
945 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
946 {
947         switch (ins->opcode) {
948         /* binops */
949         case CEE_ADD:
950         case CEE_SUB:
951         case CEE_MUL:
952         case CEE_DIV:
953         case CEE_REM:
954                 /* FIXME: check unverifiable args for STACK_MP */
955                 ins->type = bin_num_table [src1->type] [src2->type];
956                 ins->opcode += binops_op_map [ins->type];
957                 break;
958         case CEE_DIV_UN:
959         case CEE_REM_UN:
960         case CEE_AND:
961         case CEE_OR:
962         case CEE_XOR:
963                 ins->type = bin_int_table [src1->type] [src2->type];
964                 ins->opcode += binops_op_map [ins->type];
965                 break;
966         case CEE_SHL:
967         case CEE_SHR:
968         case CEE_SHR_UN:
969                 ins->type = shift_table [src1->type] [src2->type];
970                 ins->opcode += binops_op_map [ins->type];
971                 break;
972         case OP_COMPARE:
973         case OP_LCOMPARE:
974         case OP_ICOMPARE:
975                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
976                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
977                         ins->opcode = OP_LCOMPARE;
978                 else if (src1->type == STACK_R4)
979                         ins->opcode = OP_RCOMPARE;
980                 else if (src1->type == STACK_R8)
981                         ins->opcode = OP_FCOMPARE;
982                 else
983                         ins->opcode = OP_ICOMPARE;
984                 break;
985         case OP_ICOMPARE_IMM:
986                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
987                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
988                         ins->opcode = OP_LCOMPARE_IMM;          
989                 break;
990         case CEE_BEQ:
991         case CEE_BGE:
992         case CEE_BGT:
993         case CEE_BLE:
994         case CEE_BLT:
995         case CEE_BNE_UN:
996         case CEE_BGE_UN:
997         case CEE_BGT_UN:
998         case CEE_BLE_UN:
999         case CEE_BLT_UN:
1000                 ins->opcode += beqops_op_map [src1->type];
1001                 break;
1002         case OP_CEQ:
1003                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
1004                 ins->opcode += ceqops_op_map [src1->type];
1005                 break;
1006         case OP_CGT:
1007         case OP_CGT_UN:
1008         case OP_CLT:
1009         case OP_CLT_UN:
1010                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
1011                 ins->opcode += ceqops_op_map [src1->type];
1012                 break;
1013         /* unops */
1014         case CEE_NEG:
1015                 ins->type = neg_table [src1->type];
1016                 ins->opcode += unops_op_map [ins->type];
1017                 break;
1018         case CEE_NOT:
1019                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1020                         ins->type = src1->type;
1021                 else
1022                         ins->type = STACK_INV;
1023                 ins->opcode += unops_op_map [ins->type];
1024                 break;
1025         case CEE_CONV_I1:
1026         case CEE_CONV_I2:
1027         case CEE_CONV_I4:
1028         case CEE_CONV_U4:
1029                 ins->type = STACK_I4;
1030                 ins->opcode += unops_op_map [src1->type];
1031                 break;
1032         case CEE_CONV_R_UN:
1033                 ins->type = STACK_R8;
1034                 switch (src1->type) {
1035                 case STACK_I4:
1036                 case STACK_PTR:
1037                         ins->opcode = OP_ICONV_TO_R_UN;
1038                         break;
1039                 case STACK_I8:
1040                         ins->opcode = OP_LCONV_TO_R_UN; 
1041                         break;
1042                 }
1043                 break;
1044         case CEE_CONV_OVF_I1:
1045         case CEE_CONV_OVF_U1:
1046         case CEE_CONV_OVF_I2:
1047         case CEE_CONV_OVF_U2:
1048         case CEE_CONV_OVF_I4:
1049         case CEE_CONV_OVF_U4:
1050                 ins->type = STACK_I4;
1051                 ins->opcode += ovf3ops_op_map [src1->type];
1052                 break;
1053         case CEE_CONV_OVF_I_UN:
1054         case CEE_CONV_OVF_U_UN:
1055                 ins->type = STACK_PTR;
1056                 ins->opcode += ovf2ops_op_map [src1->type];
1057                 break;
1058         case CEE_CONV_OVF_I1_UN:
1059         case CEE_CONV_OVF_I2_UN:
1060         case CEE_CONV_OVF_I4_UN:
1061         case CEE_CONV_OVF_U1_UN:
1062         case CEE_CONV_OVF_U2_UN:
1063         case CEE_CONV_OVF_U4_UN:
1064                 ins->type = STACK_I4;
1065                 ins->opcode += ovf2ops_op_map [src1->type];
1066                 break;
1067         case CEE_CONV_U:
1068                 ins->type = STACK_PTR;
1069                 switch (src1->type) {
1070                 case STACK_I4:
1071                         ins->opcode = OP_ICONV_TO_U;
1072                         break;
1073                 case STACK_PTR:
1074                 case STACK_MP:
1075 #if SIZEOF_VOID_P == 8
1076                         ins->opcode = OP_LCONV_TO_U;
1077 #else
1078                         ins->opcode = OP_MOVE;
1079 #endif
1080                         break;
1081                 case STACK_I8:
1082                         ins->opcode = OP_LCONV_TO_U;
1083                         break;
1084                 case STACK_R8:
1085                         ins->opcode = OP_FCONV_TO_U;
1086                         break;
1087                 }
1088                 break;
1089         case CEE_CONV_I8:
1090         case CEE_CONV_U8:
1091                 ins->type = STACK_I8;
1092                 ins->opcode += unops_op_map [src1->type];
1093                 break;
1094         case CEE_CONV_OVF_I8:
1095         case CEE_CONV_OVF_U8:
1096                 ins->type = STACK_I8;
1097                 ins->opcode += ovf3ops_op_map [src1->type];
1098                 break;
1099         case CEE_CONV_OVF_U8_UN:
1100         case CEE_CONV_OVF_I8_UN:
1101                 ins->type = STACK_I8;
1102                 ins->opcode += ovf2ops_op_map [src1->type];
1103                 break;
1104         case CEE_CONV_R4:
1105                 ins->type = cfg->r4_stack_type;
1106                 ins->opcode += unops_op_map [src1->type];
1107                 break;
1108         case CEE_CONV_R8:
1109                 ins->type = STACK_R8;
1110                 ins->opcode += unops_op_map [src1->type];
1111                 break;
1112         case OP_CKFINITE:
1113                 ins->type = STACK_R8;           
1114                 break;
1115         case CEE_CONV_U2:
1116         case CEE_CONV_U1:
1117                 ins->type = STACK_I4;
1118                 ins->opcode += ovfops_op_map [src1->type];
1119                 break;
1120         case CEE_CONV_I:
1121         case CEE_CONV_OVF_I:
1122         case CEE_CONV_OVF_U:
1123                 ins->type = STACK_PTR;
1124                 ins->opcode += ovfops_op_map [src1->type];
1125                 break;
1126         case CEE_ADD_OVF:
1127         case CEE_ADD_OVF_UN:
1128         case CEE_MUL_OVF:
1129         case CEE_MUL_OVF_UN:
1130         case CEE_SUB_OVF:
1131         case CEE_SUB_OVF_UN:
1132                 ins->type = bin_num_table [src1->type] [src2->type];
1133                 ins->opcode += ovfops_op_map [src1->type];
1134                 if (ins->type == STACK_R8)
1135                         ins->type = STACK_INV;
1136                 break;
1137         case OP_LOAD_MEMBASE:
1138                 ins->type = STACK_PTR;
1139                 break;
1140         case OP_LOADI1_MEMBASE:
1141         case OP_LOADU1_MEMBASE:
1142         case OP_LOADI2_MEMBASE:
1143         case OP_LOADU2_MEMBASE:
1144         case OP_LOADI4_MEMBASE:
1145         case OP_LOADU4_MEMBASE:
1146                 ins->type = STACK_PTR;
1147                 break;
1148         case OP_LOADI8_MEMBASE:
1149                 ins->type = STACK_I8;
1150                 break;
1151         case OP_LOADR4_MEMBASE:
1152                 ins->type = cfg->r4_stack_type;
1153                 break;
1154         case OP_LOADR8_MEMBASE:
1155                 ins->type = STACK_R8;
1156                 break;
1157         default:
1158                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1159                 break;
1160         }
1161
1162         if (ins->type == STACK_MP)
1163                 ins->klass = mono_defaults.object_class;
1164 }
1165
1166 static const char 
1167 ldind_type [] = {
1168         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1169 };
1170
1171 #if 0
1172
1173 static const char
1174 param_table [STACK_MAX] [STACK_MAX] = {
1175         {0},
1176 };
1177
1178 static int
1179 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1180 {
1181         int i;
1182
1183         if (sig->hasthis) {
1184                 switch (args->type) {
1185                 case STACK_I4:
1186                 case STACK_I8:
1187                 case STACK_R8:
1188                 case STACK_VTYPE:
1189                 case STACK_INV:
1190                         return 0;
1191                 }
1192                 args++;
1193         }
1194         for (i = 0; i < sig->param_count; ++i) {
1195                 switch (args [i].type) {
1196                 case STACK_INV:
1197                         return 0;
1198                 case STACK_MP:
1199                         if (!sig->params [i]->byref)
1200                                 return 0;
1201                         continue;
1202                 case STACK_OBJ:
1203                         if (sig->params [i]->byref)
1204                                 return 0;
1205                         switch (sig->params [i]->type) {
1206                         case MONO_TYPE_CLASS:
1207                         case MONO_TYPE_STRING:
1208                         case MONO_TYPE_OBJECT:
1209                         case MONO_TYPE_SZARRAY:
1210                         case MONO_TYPE_ARRAY:
1211                                 break;
1212                         default:
1213                                 return 0;
1214                         }
1215                         continue;
1216                 case STACK_R8:
1217                         if (sig->params [i]->byref)
1218                                 return 0;
1219                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1220                                 return 0;
1221                         continue;
1222                 case STACK_PTR:
1223                 case STACK_I4:
1224                 case STACK_I8:
1225                 case STACK_VTYPE:
1226                         break;
1227                 }
1228                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1229                         return 0;*/
1230         }
1231         return 1;
1232 }
1233 #endif
1234
1235 /*
1236  * When we need a pointer to the current domain many times in a method, we
1237  * call mono_domain_get() once and we store the result in a local variable.
1238  * This function returns the variable that represents the MonoDomain*.
1239  */
1240 inline static MonoInst *
1241 mono_get_domainvar (MonoCompile *cfg)
1242 {
1243         if (!cfg->domainvar)
1244                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1245         return cfg->domainvar;
1246 }
1247
1248 /*
1249  * The got_var contains the address of the Global Offset Table when AOT 
1250  * compiling.
1251  */
1252 MonoInst *
1253 mono_get_got_var (MonoCompile *cfg)
1254 {
1255         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1256                 return NULL;
1257         if (!cfg->got_var) {
1258                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1259         }
1260         return cfg->got_var;
1261 }
1262
1263 static MonoInst *
1264 mono_get_vtable_var (MonoCompile *cfg)
1265 {
1266         g_assert (cfg->gshared);
1267
1268         if (!cfg->rgctx_var) {
1269                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1270                 /* force the var to be stack allocated */
1271                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1272         }
1273
1274         return cfg->rgctx_var;
1275 }
1276
1277 static MonoType*
1278 type_from_stack_type (MonoInst *ins) {
1279         switch (ins->type) {
1280         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1281         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1282         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1283         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1284         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1285         case STACK_MP:
1286                 return &ins->klass->this_arg;
1287         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1288         case STACK_VTYPE: return &ins->klass->byval_arg;
1289         default:
1290                 g_error ("stack type %d to monotype not handled\n", ins->type);
1291         }
1292         return NULL;
1293 }
1294
1295 static G_GNUC_UNUSED int
1296 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1297 {
1298         t = mono_type_get_underlying_type (t);
1299         switch (t->type) {
1300         case MONO_TYPE_I1:
1301         case MONO_TYPE_U1:
1302         case MONO_TYPE_I2:
1303         case MONO_TYPE_U2:
1304         case MONO_TYPE_I4:
1305         case MONO_TYPE_U4:
1306                 return STACK_I4;
1307         case MONO_TYPE_I:
1308         case MONO_TYPE_U:
1309         case MONO_TYPE_PTR:
1310         case MONO_TYPE_FNPTR:
1311                 return STACK_PTR;
1312         case MONO_TYPE_CLASS:
1313         case MONO_TYPE_STRING:
1314         case MONO_TYPE_OBJECT:
1315         case MONO_TYPE_SZARRAY:
1316         case MONO_TYPE_ARRAY:    
1317                 return STACK_OBJ;
1318         case MONO_TYPE_I8:
1319         case MONO_TYPE_U8:
1320                 return STACK_I8;
1321         case MONO_TYPE_R4:
1322                 return cfg->r4_stack_type;
1323         case MONO_TYPE_R8:
1324                 return STACK_R8;
1325         case MONO_TYPE_VALUETYPE:
1326         case MONO_TYPE_TYPEDBYREF:
1327                 return STACK_VTYPE;
1328         case MONO_TYPE_GENERICINST:
1329                 if (mono_type_generic_inst_is_valuetype (t))
1330                         return STACK_VTYPE;
1331                 else
1332                         return STACK_OBJ;
1333                 break;
1334         default:
1335                 g_assert_not_reached ();
1336         }
1337
1338         return -1;
1339 }
1340
1341 static MonoClass*
1342 array_access_to_klass (int opcode)
1343 {
1344         switch (opcode) {
1345         case CEE_LDELEM_U1:
1346                 return mono_defaults.byte_class;
1347         case CEE_LDELEM_U2:
1348                 return mono_defaults.uint16_class;
1349         case CEE_LDELEM_I:
1350         case CEE_STELEM_I:
1351                 return mono_defaults.int_class;
1352         case CEE_LDELEM_I1:
1353         case CEE_STELEM_I1:
1354                 return mono_defaults.sbyte_class;
1355         case CEE_LDELEM_I2:
1356         case CEE_STELEM_I2:
1357                 return mono_defaults.int16_class;
1358         case CEE_LDELEM_I4:
1359         case CEE_STELEM_I4:
1360                 return mono_defaults.int32_class;
1361         case CEE_LDELEM_U4:
1362                 return mono_defaults.uint32_class;
1363         case CEE_LDELEM_I8:
1364         case CEE_STELEM_I8:
1365                 return mono_defaults.int64_class;
1366         case CEE_LDELEM_R4:
1367         case CEE_STELEM_R4:
1368                 return mono_defaults.single_class;
1369         case CEE_LDELEM_R8:
1370         case CEE_STELEM_R8:
1371                 return mono_defaults.double_class;
1372         case CEE_LDELEM_REF:
1373         case CEE_STELEM_REF:
1374                 return mono_defaults.object_class;
1375         default:
1376                 g_assert_not_reached ();
1377         }
1378         return NULL;
1379 }
1380
1381 /*
1382  * We try to share variables when possible
1383  */
1384 static MonoInst *
1385 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1386 {
1387         MonoInst *res;
1388         int pos, vnum;
1389
1390         /* inlining can result in deeper stacks */ 
1391         if (slot >= cfg->header->max_stack)
1392                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1393
1394         pos = ins->type - 1 + slot * STACK_MAX;
1395
1396         switch (ins->type) {
1397         case STACK_I4:
1398         case STACK_I8:
1399         case STACK_R8:
1400         case STACK_PTR:
1401         case STACK_MP:
1402         case STACK_OBJ:
1403                 if ((vnum = cfg->intvars [pos]))
1404                         return cfg->varinfo [vnum];
1405                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1406                 cfg->intvars [pos] = res->inst_c0;
1407                 break;
1408         default:
1409                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1410         }
1411         return res;
1412 }
1413
1414 static void
1415 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1416 {
1417         /* 
1418          * Don't use this if a generic_context is set, since that means AOT can't
1419          * look up the method using just the image+token.
1420          * table == 0 means this is a reference made from a wrapper.
1421          */
1422         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1423                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1424                 jump_info_token->image = image;
1425                 jump_info_token->token = token;
1426                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1427         }
1428 }
1429
1430 /*
1431  * This function is called to handle items that are left on the evaluation stack
1432  * at basic block boundaries. What happens is that we save the values to local variables
1433  * and we reload them later when first entering the target basic block (with the
1434  * handle_loaded_temps () function).
1435  * A single joint point will use the same variables (stored in the array bb->out_stack or
1436  * bb->in_stack, if the basic block is before or after the joint point).
1437  *
1438  * This function needs to be called _before_ emitting the last instruction of
1439  * the bb (i.e. before emitting a branch).
1440  * If the stack merge fails at a join point, cfg->unverifiable is set.
1441  */
1442 static void
1443 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1444 {
1445         int i, bindex;
1446         MonoBasicBlock *bb = cfg->cbb;
1447         MonoBasicBlock *outb;
1448         MonoInst *inst, **locals;
1449         gboolean found;
1450
1451         if (!count)
1452                 return;
1453         if (cfg->verbose_level > 3)
1454                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1455         if (!bb->out_scount) {
1456                 bb->out_scount = count;
1457                 //printf ("bblock %d has out:", bb->block_num);
1458                 found = FALSE;
1459                 for (i = 0; i < bb->out_count; ++i) {
1460                         outb = bb->out_bb [i];
1461                         /* exception handlers are linked, but they should not be considered for stack args */
1462                         if (outb->flags & BB_EXCEPTION_HANDLER)
1463                                 continue;
1464                         //printf (" %d", outb->block_num);
1465                         if (outb->in_stack) {
1466                                 found = TRUE;
1467                                 bb->out_stack = outb->in_stack;
1468                                 break;
1469                         }
1470                 }
1471                 //printf ("\n");
1472                 if (!found) {
1473                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1474                         for (i = 0; i < count; ++i) {
1475                                 /* 
1476                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1477                                  * stack slot and if they are of the same type.
1478                                  * This won't cause conflicts since if 'local' is used to 
1479                                  * store one of the values in the in_stack of a bblock, then
1480                                  * the same variable will be used for the same outgoing stack 
1481                                  * slot as well. 
1482                                  * This doesn't work when inlining methods, since the bblocks
1483                                  * in the inlined methods do not inherit their in_stack from
1484                                  * the bblock they are inlined to. See bug #58863 for an
1485                                  * example.
1486                                  */
1487                                 if (cfg->inlined_method)
1488                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1489                                 else
1490                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1491                         }
1492                 }
1493         }
1494
1495         for (i = 0; i < bb->out_count; ++i) {
1496                 outb = bb->out_bb [i];
1497                 /* exception handlers are linked, but they should not be considered for stack args */
1498                 if (outb->flags & BB_EXCEPTION_HANDLER)
1499                         continue;
1500                 if (outb->in_scount) {
1501                         if (outb->in_scount != bb->out_scount) {
1502                                 cfg->unverifiable = TRUE;
1503                                 return;
1504                         }
1505                         continue; /* check they are the same locals */
1506                 }
1507                 outb->in_scount = count;
1508                 outb->in_stack = bb->out_stack;
1509         }
1510
1511         locals = bb->out_stack;
1512         cfg->cbb = bb;
1513         for (i = 0; i < count; ++i) {
1514                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1515                 inst->cil_code = sp [i]->cil_code;
1516                 sp [i] = locals [i];
1517                 if (cfg->verbose_level > 3)
1518                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1519         }
1520
1521         /*
1522          * It is possible that the out bblocks already have in_stack assigned, and
1523          * the in_stacks differ. In this case, we will store to all the different 
1524          * in_stacks.
1525          */
1526
1527         found = TRUE;
1528         bindex = 0;
1529         while (found) {
1530                 /* Find a bblock which has a different in_stack */
1531                 found = FALSE;
1532                 while (bindex < bb->out_count) {
1533                         outb = bb->out_bb [bindex];
1534                         /* exception handlers are linked, but they should not be considered for stack args */
1535                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1536                                 bindex++;
1537                                 continue;
1538                         }
1539                         if (outb->in_stack != locals) {
1540                                 for (i = 0; i < count; ++i) {
1541                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1542                                         inst->cil_code = sp [i]->cil_code;
1543                                         sp [i] = locals [i];
1544                                         if (cfg->verbose_level > 3)
1545                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1546                                 }
1547                                 locals = outb->in_stack;
1548                                 found = TRUE;
1549                                 break;
1550                         }
1551                         bindex ++;
1552                 }
1553         }
1554 }
1555
1556 static MonoInst*
1557 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1558 {
1559         MonoInst *ins;
1560
1561         if (cfg->compile_aot) {
1562                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1563         } else {
1564                 MonoJumpInfo ji;
1565                 gpointer target;
1566                 MonoError error;
1567
1568                 ji.type = patch_type;
1569                 ji.data.target = data;
1570                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1571                 mono_error_assert_ok (&error);
1572
1573                 EMIT_NEW_PCONST (cfg, ins, target);
1574         }
1575         return ins;
1576 }
1577
1578 MonoInst*
1579 mini_emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1580 {
1581         return emit_runtime_constant (cfg, patch_type, data);
1582 }
1583
1584 static void 
1585 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1586 {
1587         int val_reg;
1588
1589         g_assert (val == 0);
1590
1591         if (align == 0)
1592                 align = 4;
1593
1594         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1595                 switch (size) {
1596                 case 1:
1597                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1598                         return;
1599                 case 2:
1600                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1601                         return;
1602                 case 4:
1603                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1604                         return;
1605 #if SIZEOF_REGISTER == 8
1606                 case 8:
1607                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1608                         return;
1609 #endif
1610                 }
1611         }
1612
1613         val_reg = alloc_preg (cfg);
1614
1615         if (SIZEOF_REGISTER == 8)
1616                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1617         else
1618                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1619
1620         if (align < 4) {
1621                 /* This could be optimized further if neccesary */
1622                 while (size >= 1) {
1623                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1624                         offset += 1;
1625                         size -= 1;
1626                 }
1627                 return;
1628         }       
1629
1630         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1631                 if (offset % 8) {
1632                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1633                         offset += 4;
1634                         size -= 4;
1635                 }
1636                 while (size >= 8) {
1637                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1638                         offset += 8;
1639                         size -= 8;
1640                 }
1641         }       
1642
1643         while (size >= 4) {
1644                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1645                 offset += 4;
1646                 size -= 4;
1647         }
1648         while (size >= 2) {
1649                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1650                 offset += 2;
1651                 size -= 2;
1652         }
1653         while (size >= 1) {
1654                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1655                 offset += 1;
1656                 size -= 1;
1657         }
1658 }
1659
1660 void 
1661 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1662 {
1663         int cur_reg;
1664
1665         if (align == 0)
1666                 align = 4;
1667
1668         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1669         g_assert (size < 10000);
1670
1671         if (align < 4) {
1672                 /* This could be optimized further if neccesary */
1673                 while (size >= 1) {
1674                         cur_reg = alloc_preg (cfg);
1675                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1676                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1677                         doffset += 1;
1678                         soffset += 1;
1679                         size -= 1;
1680                 }
1681         }
1682
1683         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1684                 while (size >= 8) {
1685                         cur_reg = alloc_preg (cfg);
1686                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1687                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1688                         doffset += 8;
1689                         soffset += 8;
1690                         size -= 8;
1691                 }
1692         }       
1693
1694         while (size >= 4) {
1695                 cur_reg = alloc_preg (cfg);
1696                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1697                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1698                 doffset += 4;
1699                 soffset += 4;
1700                 size -= 4;
1701         }
1702         while (size >= 2) {
1703                 cur_reg = alloc_preg (cfg);
1704                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1705                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1706                 doffset += 2;
1707                 soffset += 2;
1708                 size -= 2;
1709         }
1710         while (size >= 1) {
1711                 cur_reg = alloc_preg (cfg);
1712                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1713                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1714                 doffset += 1;
1715                 soffset += 1;
1716                 size -= 1;
1717         }
1718 }
1719
1720 static MonoInst*
1721 mono_create_fast_tls_getter (MonoCompile *cfg, MonoTlsKey key)
1722 {
1723         int tls_offset = mono_tls_get_tls_offset (key);
1724
1725         if (cfg->compile_aot)
1726                 return NULL;
1727
1728         if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
1729                 MonoInst *ins;
1730                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
1731                 ins->dreg = mono_alloc_preg (cfg);
1732                 ins->inst_offset = tls_offset;
1733                 return ins;
1734         }
1735         return NULL;
1736 }
1737
1738 static MonoInst*
1739 mono_create_fast_tls_setter (MonoCompile *cfg, MonoInst* value, MonoTlsKey key)
1740 {
1741         int tls_offset = mono_tls_get_tls_offset (key);
1742
1743         if (cfg->compile_aot)
1744                 return NULL;
1745
1746         if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
1747                 MonoInst *ins;
1748                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1749                 ins->sreg1 = value->dreg;
1750                 ins->inst_offset = tls_offset;
1751                 return ins;
1752         }
1753         return NULL;
1754 }
1755
1756
1757 MonoInst*
1758 mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key)
1759 {
1760         MonoInst *fast_tls = NULL;
1761
1762         if (!mini_get_debug_options ()->use_fallback_tls)
1763                 fast_tls = mono_create_fast_tls_getter (cfg, key);
1764
1765         if (fast_tls) {
1766                 MONO_ADD_INS (cfg->cbb, fast_tls);
1767                 return fast_tls;
1768         }
1769
1770         if (cfg->compile_aot) {
1771                 MonoInst *addr;
1772                 /*
1773                  * tls getters are critical pieces of code and we don't want to resolve them
1774                  * through the standard plt/tramp mechanism since we might expose ourselves
1775                  * to crashes and infinite recursions.
1776                  */
1777                 EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GET_TLS_TRAMP, (void*)key);
1778                 return mono_emit_calli (cfg, helper_sig_get_tls_tramp, NULL, addr, NULL, NULL);
1779         } else {
1780                 gpointer getter = mono_tls_get_tls_getter (key, FALSE);
1781                 return mono_emit_jit_icall (cfg, getter, NULL);
1782         }
1783 }
1784
1785 static MonoInst*
1786 mono_create_tls_set (MonoCompile *cfg, MonoInst *value, MonoTlsKey key)
1787 {
1788         MonoInst *fast_tls = NULL;
1789
1790         if (!mini_get_debug_options ()->use_fallback_tls)
1791                 fast_tls = mono_create_fast_tls_setter (cfg, value, key);
1792
1793         if (fast_tls) {
1794                 MONO_ADD_INS (cfg->cbb, fast_tls);
1795                 return fast_tls;
1796         }
1797
1798         if (cfg->compile_aot) {
1799                 MonoInst *addr;
1800                 EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_SET_TLS_TRAMP, (void*)key);
1801                 return mono_emit_calli (cfg, helper_sig_set_tls_tramp, &value, addr, NULL, NULL);
1802         } else {
1803                 gpointer setter = mono_tls_get_tls_setter (key, FALSE);
1804                 return mono_emit_jit_icall (cfg, setter, &value);
1805         }
1806 }
1807
1808 /*
1809  * emit_push_lmf:
1810  *
1811  *   Emit IR to push the current LMF onto the LMF stack.
1812  */
1813 static void
1814 emit_push_lmf (MonoCompile *cfg)
1815 {
1816         /*
1817          * Emit IR to push the LMF:
1818          * lmf_addr = <lmf_addr from tls>
1819          * lmf->lmf_addr = lmf_addr
1820          * lmf->prev_lmf = *lmf_addr
1821          * *lmf_addr = lmf
1822          */
1823         MonoInst *ins, *lmf_ins;
1824
1825         if (!cfg->lmf_ir)
1826                 return;
1827
1828         if (cfg->lmf_ir_mono_lmf) {
1829                 MonoInst *lmf_vara_ins, *lmf_ins;
1830                 /* Load current lmf */
1831                 lmf_ins = mono_create_tls_get (cfg, TLS_KEY_LMF);
1832                 g_assert (lmf_ins);
1833                 EMIT_NEW_VARLOADA (cfg, lmf_vara_ins, cfg->lmf_var, NULL);
1834                 /* Save previous_lmf */
1835                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_vara_ins->dreg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1836                 /* Set new LMF */
1837                 mono_create_tls_set (cfg, lmf_vara_ins, TLS_KEY_LMF);
1838         } else {
1839                 int lmf_reg, prev_lmf_reg;
1840                 /*
1841                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1842                  */
1843                 if (!cfg->lmf_addr_var)
1844                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1845
1846 #ifdef HOST_WIN32
1847                 ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
1848                 g_assert (ins);
1849                 int jit_tls_dreg = ins->dreg;
1850
1851                 lmf_reg = alloc_preg (cfg);
1852                 EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
1853 #else
1854                 lmf_ins = mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR);
1855                 g_assert (lmf_ins);
1856 #endif
1857                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
1858
1859                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1860                 lmf_reg = ins->dreg;
1861
1862                 prev_lmf_reg = alloc_preg (cfg);
1863                 /* Save previous_lmf */
1864                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
1865                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
1866                 /* Set new lmf */
1867                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
1868         }
1869 }
1870
1871 /*
1872  * emit_pop_lmf:
1873  *
1874  *   Emit IR to pop the current LMF from the LMF stack.
1875  */
1876 static void
1877 emit_pop_lmf (MonoCompile *cfg)
1878 {
1879         int lmf_reg, lmf_addr_reg;
1880         MonoInst *ins;
1881
1882         if (!cfg->lmf_ir)
1883                 return;
1884
1885         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1886         lmf_reg = ins->dreg;
1887
1888         if (cfg->lmf_ir_mono_lmf) {
1889                 /* Load previous_lmf */
1890                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, alloc_preg (cfg), lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1891                 /* Set new LMF */
1892                 mono_create_tls_set (cfg, ins, TLS_KEY_LMF);
1893         } else {
1894                 int prev_lmf_reg;
1895                 /*
1896                  * Emit IR to pop the LMF:
1897                  * *(lmf->lmf_addr) = lmf->prev_lmf
1898                  */
1899                 /* This could be called before emit_push_lmf () */
1900                 if (!cfg->lmf_addr_var)
1901                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1902                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
1903
1904                 prev_lmf_reg = alloc_preg (cfg);
1905                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1906                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
1907         }
1908 }
1909
1910 static void
1911 emit_instrumentation_call (MonoCompile *cfg, void *func)
1912 {
1913         MonoInst *iargs [1];
1914
1915         /*
1916          * Avoid instrumenting inlined methods since it can
1917          * distort profiling results.
1918          */
1919         if (cfg->method != cfg->current_method)
1920                 return;
1921
1922         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
1923                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
1924                 mono_emit_jit_icall (cfg, func, iargs);
1925         }
1926 }
1927
1928 static int
1929 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
1930 {
1931 handle_enum:
1932         type = mini_get_underlying_type (type);
1933         switch (type->type) {
1934         case MONO_TYPE_VOID:
1935                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
1936         case MONO_TYPE_I1:
1937         case MONO_TYPE_U1:
1938         case MONO_TYPE_I2:
1939         case MONO_TYPE_U2:
1940         case MONO_TYPE_I4:
1941         case MONO_TYPE_U4:
1942                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1943         case MONO_TYPE_I:
1944         case MONO_TYPE_U:
1945         case MONO_TYPE_PTR:
1946         case MONO_TYPE_FNPTR:
1947                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1948         case MONO_TYPE_CLASS:
1949         case MONO_TYPE_STRING:
1950         case MONO_TYPE_OBJECT:
1951         case MONO_TYPE_SZARRAY:
1952         case MONO_TYPE_ARRAY:    
1953                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1954         case MONO_TYPE_I8:
1955         case MONO_TYPE_U8:
1956                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
1957         case MONO_TYPE_R4:
1958                 if (cfg->r4fp)
1959                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
1960                 else
1961                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1962         case MONO_TYPE_R8:
1963                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1964         case MONO_TYPE_VALUETYPE:
1965                 if (type->data.klass->enumtype) {
1966                         type = mono_class_enum_basetype (type->data.klass);
1967                         goto handle_enum;
1968                 } else
1969                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1970         case MONO_TYPE_TYPEDBYREF:
1971                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1972         case MONO_TYPE_GENERICINST:
1973                 type = &type->data.generic_class->container_class->byval_arg;
1974                 goto handle_enum;
1975         case MONO_TYPE_VAR:
1976         case MONO_TYPE_MVAR:
1977                 /* gsharedvt */
1978                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1979         default:
1980                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1981         }
1982         return -1;
1983 }
1984
1985 //XXX this ignores if t is byref
1986 #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)))))
1987
1988 /*
1989  * target_type_is_incompatible:
1990  * @cfg: MonoCompile context
1991  *
1992  * Check that the item @arg on the evaluation stack can be stored
1993  * in the target type (can be a local, or field, etc).
1994  * The cfg arg can be used to check if we need verification or just
1995  * validity checks.
1996  *
1997  * Returns: non-0 value if arg can't be stored on a target.
1998  */
1999 static int
2000 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2001 {
2002         MonoType *simple_type;
2003         MonoClass *klass;
2004
2005         if (target->byref) {
2006                 /* FIXME: check that the pointed to types match */
2007                 if (arg->type == STACK_MP) {
2008                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
2009                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
2010                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
2011
2012                         /* if the target is native int& or same type */
2013                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
2014                                 return 0;
2015
2016                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
2017                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
2018                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
2019                                 return 0;
2020                         return 1;
2021                 }
2022                 if (arg->type == STACK_PTR)
2023                         return 0;
2024                 return 1;
2025         }
2026
2027         simple_type = mini_get_underlying_type (target);
2028         switch (simple_type->type) {
2029         case MONO_TYPE_VOID:
2030                 return 1;
2031         case MONO_TYPE_I1:
2032         case MONO_TYPE_U1:
2033         case MONO_TYPE_I2:
2034         case MONO_TYPE_U2:
2035         case MONO_TYPE_I4:
2036         case MONO_TYPE_U4:
2037                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2038                         return 1;
2039                 return 0;
2040         case MONO_TYPE_PTR:
2041                 /* STACK_MP is needed when setting pinned locals */
2042                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2043                         return 1;
2044                 return 0;
2045         case MONO_TYPE_I:
2046         case MONO_TYPE_U:
2047         case MONO_TYPE_FNPTR:
2048                 /* 
2049                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2050                  * in native int. (#688008).
2051                  */
2052                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2053                         return 1;
2054                 return 0;
2055         case MONO_TYPE_CLASS:
2056         case MONO_TYPE_STRING:
2057         case MONO_TYPE_OBJECT:
2058         case MONO_TYPE_SZARRAY:
2059         case MONO_TYPE_ARRAY:    
2060                 if (arg->type != STACK_OBJ)
2061                         return 1;
2062                 /* FIXME: check type compatibility */
2063                 return 0;
2064         case MONO_TYPE_I8:
2065         case MONO_TYPE_U8:
2066                 if (arg->type != STACK_I8)
2067                         return 1;
2068                 return 0;
2069         case MONO_TYPE_R4:
2070                 if (arg->type != cfg->r4_stack_type)
2071                         return 1;
2072                 return 0;
2073         case MONO_TYPE_R8:
2074                 if (arg->type != STACK_R8)
2075                         return 1;
2076                 return 0;
2077         case MONO_TYPE_VALUETYPE:
2078                 if (arg->type != STACK_VTYPE)
2079                         return 1;
2080                 klass = mono_class_from_mono_type (simple_type);
2081                 if (klass != arg->klass)
2082                         return 1;
2083                 return 0;
2084         case MONO_TYPE_TYPEDBYREF:
2085                 if (arg->type != STACK_VTYPE)
2086                         return 1;
2087                 klass = mono_class_from_mono_type (simple_type);
2088                 if (klass != arg->klass)
2089                         return 1;
2090                 return 0;
2091         case MONO_TYPE_GENERICINST:
2092                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2093                         MonoClass *target_class;
2094                         if (arg->type != STACK_VTYPE)
2095                                 return 1;
2096                         klass = mono_class_from_mono_type (simple_type);
2097                         target_class = mono_class_from_mono_type (target);
2098                         /* The second cases is needed when doing partial sharing */
2099                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2100                                 return 1;
2101                         return 0;
2102                 } else {
2103                         if (arg->type != STACK_OBJ)
2104                                 return 1;
2105                         /* FIXME: check type compatibility */
2106                         return 0;
2107                 }
2108         case MONO_TYPE_VAR:
2109         case MONO_TYPE_MVAR:
2110                 g_assert (cfg->gshared);
2111                 if (mini_type_var_is_vt (simple_type)) {
2112                         if (arg->type != STACK_VTYPE)
2113                                 return 1;
2114                 } else {
2115                         if (arg->type != STACK_OBJ)
2116                                 return 1;
2117                 }
2118                 return 0;
2119         default:
2120                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2121         }
2122         return 1;
2123 }
2124
2125 /*
2126  * Prepare arguments for passing to a function call.
2127  * Return a non-zero value if the arguments can't be passed to the given
2128  * signature.
2129  * The type checks are not yet complete and some conversions may need
2130  * casts on 32 or 64 bit architectures.
2131  *
2132  * FIXME: implement this using target_type_is_incompatible ()
2133  */
2134 static int
2135 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2136 {
2137         MonoType *simple_type;
2138         int i;
2139
2140         if (sig->hasthis) {
2141                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2142                         return 1;
2143                 args++;
2144         }
2145         for (i = 0; i < sig->param_count; ++i) {
2146                 if (sig->params [i]->byref) {
2147                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2148                                 return 1;
2149                         continue;
2150                 }
2151                 simple_type = mini_get_underlying_type (sig->params [i]);
2152 handle_enum:
2153                 switch (simple_type->type) {
2154                 case MONO_TYPE_VOID:
2155                         return 1;
2156                         continue;
2157                 case MONO_TYPE_I1:
2158                 case MONO_TYPE_U1:
2159                 case MONO_TYPE_I2:
2160                 case MONO_TYPE_U2:
2161                 case MONO_TYPE_I4:
2162                 case MONO_TYPE_U4:
2163                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2164                                 return 1;
2165                         continue;
2166                 case MONO_TYPE_I:
2167                 case MONO_TYPE_U:
2168                 case MONO_TYPE_PTR:
2169                 case MONO_TYPE_FNPTR:
2170                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2171                                 return 1;
2172                         continue;
2173                 case MONO_TYPE_CLASS:
2174                 case MONO_TYPE_STRING:
2175                 case MONO_TYPE_OBJECT:
2176                 case MONO_TYPE_SZARRAY:
2177                 case MONO_TYPE_ARRAY:    
2178                         if (args [i]->type != STACK_OBJ)
2179                                 return 1;
2180                         continue;
2181                 case MONO_TYPE_I8:
2182                 case MONO_TYPE_U8:
2183                         if (args [i]->type != STACK_I8)
2184                                 return 1;
2185                         continue;
2186                 case MONO_TYPE_R4:
2187                         if (args [i]->type != cfg->r4_stack_type)
2188                                 return 1;
2189                         continue;
2190                 case MONO_TYPE_R8:
2191                         if (args [i]->type != STACK_R8)
2192                                 return 1;
2193                         continue;
2194                 case MONO_TYPE_VALUETYPE:
2195                         if (simple_type->data.klass->enumtype) {
2196                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2197                                 goto handle_enum;
2198                         }
2199                         if (args [i]->type != STACK_VTYPE)
2200                                 return 1;
2201                         continue;
2202                 case MONO_TYPE_TYPEDBYREF:
2203                         if (args [i]->type != STACK_VTYPE)
2204                                 return 1;
2205                         continue;
2206                 case MONO_TYPE_GENERICINST:
2207                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2208                         goto handle_enum;
2209                 case MONO_TYPE_VAR:
2210                 case MONO_TYPE_MVAR:
2211                         /* gsharedvt */
2212                         if (args [i]->type != STACK_VTYPE)
2213                                 return 1;
2214                         continue;
2215                 default:
2216                         g_error ("unknown type 0x%02x in check_call_signature",
2217                                  simple_type->type);
2218                 }
2219         }
2220         return 0;
2221 }
2222
2223 static int
2224 callvirt_to_call (int opcode)
2225 {
2226         switch (opcode) {
2227         case OP_CALL_MEMBASE:
2228                 return OP_CALL;
2229         case OP_VOIDCALL_MEMBASE:
2230                 return OP_VOIDCALL;
2231         case OP_FCALL_MEMBASE:
2232                 return OP_FCALL;
2233         case OP_RCALL_MEMBASE:
2234                 return OP_RCALL;
2235         case OP_VCALL_MEMBASE:
2236                 return OP_VCALL;
2237         case OP_LCALL_MEMBASE:
2238                 return OP_LCALL;
2239         default:
2240                 g_assert_not_reached ();
2241         }
2242
2243         return -1;
2244 }
2245
2246 static int
2247 callvirt_to_call_reg (int opcode)
2248 {
2249         switch (opcode) {
2250         case OP_CALL_MEMBASE:
2251                 return OP_CALL_REG;
2252         case OP_VOIDCALL_MEMBASE:
2253                 return OP_VOIDCALL_REG;
2254         case OP_FCALL_MEMBASE:
2255                 return OP_FCALL_REG;
2256         case OP_RCALL_MEMBASE:
2257                 return OP_RCALL_REG;
2258         case OP_VCALL_MEMBASE:
2259                 return OP_VCALL_REG;
2260         case OP_LCALL_MEMBASE:
2261                 return OP_LCALL_REG;
2262         default:
2263                 g_assert_not_reached ();
2264         }
2265
2266         return -1;
2267 }
2268
2269 /* Either METHOD or IMT_ARG needs to be set */
2270 static void
2271 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2272 {
2273         int method_reg;
2274
2275         if (COMPILE_LLVM (cfg)) {
2276                 if (imt_arg) {
2277                         method_reg = alloc_preg (cfg);
2278                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2279                 } else {
2280                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2281                         method_reg = ins->dreg;
2282                 }
2283
2284 #ifdef ENABLE_LLVM
2285                 call->imt_arg_reg = method_reg;
2286 #endif
2287                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2288                 return;
2289         }
2290
2291         if (imt_arg) {
2292                 method_reg = alloc_preg (cfg);
2293                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2294         } else {
2295                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2296                 method_reg = ins->dreg;
2297         }
2298
2299         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2300 }
2301
2302 static MonoJumpInfo *
2303 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2304 {
2305         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2306
2307         ji->ip.i = ip;
2308         ji->type = type;
2309         ji->data.target = target;
2310
2311         return ji;
2312 }
2313
2314 static int
2315 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2316 {
2317         if (cfg->gshared)
2318                 return mono_class_check_context_used (klass);
2319         else
2320                 return 0;
2321 }
2322
2323 static int
2324 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2325 {
2326         if (cfg->gshared)
2327                 return mono_method_check_context_used (method);
2328         else
2329                 return 0;
2330 }
2331
2332 /*
2333  * check_method_sharing:
2334  *
2335  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2336  */
2337 static void
2338 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2339 {
2340         gboolean pass_vtable = FALSE;
2341         gboolean pass_mrgctx = FALSE;
2342
2343         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2344                 (mono_class_is_ginst (cmethod->klass) || mono_class_is_gtd (cmethod->klass))) {
2345                 gboolean sharable = FALSE;
2346
2347                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2348                         sharable = TRUE;
2349
2350                 /*
2351                  * Pass vtable iff target method might
2352                  * be shared, which means that sharing
2353                  * is enabled for its class and its
2354                  * context is sharable (and it's not a
2355                  * generic method).
2356                  */
2357                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2358                         pass_vtable = TRUE;
2359         }
2360
2361         if (mini_method_get_context (cmethod) &&
2362                 mini_method_get_context (cmethod)->method_inst) {
2363                 g_assert (!pass_vtable);
2364
2365                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2366                         pass_mrgctx = TRUE;
2367                 } else {
2368                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2369                                 pass_mrgctx = TRUE;
2370                 }
2371         }
2372
2373         if (out_pass_vtable)
2374                 *out_pass_vtable = pass_vtable;
2375         if (out_pass_mrgctx)
2376                 *out_pass_mrgctx = pass_mrgctx;
2377 }
2378
2379 inline static MonoCallInst *
2380 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2381                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2382 {
2383         MonoType *sig_ret;
2384         MonoCallInst *call;
2385 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2386         int i;
2387 #endif
2388
2389         if (cfg->llvm_only)
2390                 tail = FALSE;
2391
2392         if (tail) {
2393                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2394
2395                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2396         } else
2397                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2398
2399         call->args = args;
2400         call->signature = sig;
2401         call->rgctx_reg = rgctx;
2402         sig_ret = mini_get_underlying_type (sig->ret);
2403
2404         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2405
2406         if (tail) {
2407                 if (mini_type_is_vtype (sig_ret)) {
2408                         call->vret_var = cfg->vret_addr;
2409                         //g_assert_not_reached ();
2410                 }
2411         } else if (mini_type_is_vtype (sig_ret)) {
2412                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2413                 MonoInst *loada;
2414
2415                 temp->backend.is_pinvoke = sig->pinvoke;
2416
2417                 /*
2418                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2419                  * address of return value to increase optimization opportunities.
2420                  * Before vtype decomposition, the dreg of the call ins itself represents the
2421                  * fact the call modifies the return value. After decomposition, the call will
2422                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2423                  * will be transformed into an LDADDR.
2424                  */
2425                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2426                 loada->dreg = alloc_preg (cfg);
2427                 loada->inst_p0 = temp;
2428                 /* We reference the call too since call->dreg could change during optimization */
2429                 loada->inst_p1 = call;
2430                 MONO_ADD_INS (cfg->cbb, loada);
2431
2432                 call->inst.dreg = temp->dreg;
2433
2434                 call->vret_var = loada;
2435         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2436                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2437
2438 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2439         if (COMPILE_SOFT_FLOAT (cfg)) {
2440                 /* 
2441                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2442                  * an icall, but that cannot be done during the call sequence since it would clobber
2443                  * the call registers + the stack. So we do it before emitting the call.
2444                  */
2445                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2446                         MonoType *t;
2447                         MonoInst *in = call->args [i];
2448
2449                         if (i >= sig->hasthis)
2450                                 t = sig->params [i - sig->hasthis];
2451                         else
2452                                 t = &mono_defaults.int_class->byval_arg;
2453                         t = mono_type_get_underlying_type (t);
2454
2455                         if (!t->byref && t->type == MONO_TYPE_R4) {
2456                                 MonoInst *iargs [1];
2457                                 MonoInst *conv;
2458
2459                                 iargs [0] = in;
2460                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2461
2462                                 /* The result will be in an int vreg */
2463                                 call->args [i] = conv;
2464                         }
2465                 }
2466         }
2467 #endif
2468
2469         call->need_unbox_trampoline = unbox_trampoline;
2470
2471 #ifdef ENABLE_LLVM
2472         if (COMPILE_LLVM (cfg))
2473                 mono_llvm_emit_call (cfg, call);
2474         else
2475                 mono_arch_emit_call (cfg, call);
2476 #else
2477         mono_arch_emit_call (cfg, call);
2478 #endif
2479
2480         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2481         cfg->flags |= MONO_CFG_HAS_CALLS;
2482         
2483         return call;
2484 }
2485
2486 static void
2487 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2488 {
2489         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2490         cfg->uses_rgctx_reg = TRUE;
2491         call->rgctx_reg = TRUE;
2492 #ifdef ENABLE_LLVM
2493         call->rgctx_arg_reg = rgctx_reg;
2494 #endif
2495 }       
2496
2497 inline static MonoInst*
2498 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2499 {
2500         MonoCallInst *call;
2501         MonoInst *ins;
2502         int rgctx_reg = -1;
2503         gboolean check_sp = FALSE;
2504
2505         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2506                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2507
2508                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2509                         check_sp = TRUE;
2510         }
2511
2512         if (rgctx_arg) {
2513                 rgctx_reg = mono_alloc_preg (cfg);
2514                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2515         }
2516
2517         if (check_sp) {
2518                 if (!cfg->stack_inbalance_var)
2519                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2520
2521                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2522                 ins->dreg = cfg->stack_inbalance_var->dreg;
2523                 MONO_ADD_INS (cfg->cbb, ins);
2524         }
2525
2526         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2527
2528         call->inst.sreg1 = addr->dreg;
2529
2530         if (imt_arg)
2531                 emit_imt_argument (cfg, call, NULL, imt_arg);
2532
2533         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2534
2535         if (check_sp) {
2536                 int sp_reg;
2537
2538                 sp_reg = mono_alloc_preg (cfg);
2539
2540                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2541                 ins->dreg = sp_reg;
2542                 MONO_ADD_INS (cfg->cbb, ins);
2543
2544                 /* Restore the stack so we don't crash when throwing the exception */
2545                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2546                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2547                 MONO_ADD_INS (cfg->cbb, ins);
2548
2549                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2550                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2551         }
2552
2553         if (rgctx_arg)
2554                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2555
2556         return (MonoInst*)call;
2557 }
2558
2559 static MonoInst*
2560 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2561
2562 static MonoInst*
2563 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2564
2565 static MonoInst*
2566 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2567                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2568 {
2569 #ifndef DISABLE_REMOTING
2570         gboolean might_be_remote = FALSE;
2571 #endif
2572         gboolean virtual_ = this_ins != NULL;
2573         gboolean enable_for_aot = TRUE;
2574         int context_used;
2575         MonoCallInst *call;
2576         MonoInst *call_target = NULL;
2577         int rgctx_reg = 0;
2578         gboolean need_unbox_trampoline;
2579
2580         if (!sig)
2581                 sig = mono_method_signature (method);
2582
2583         if (cfg->llvm_only && (mono_class_is_interface (method->klass)))
2584                 g_assert_not_reached ();
2585
2586         if (rgctx_arg) {
2587                 rgctx_reg = mono_alloc_preg (cfg);
2588                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2589         }
2590
2591         if (method->string_ctor) {
2592                 /* Create the real signature */
2593                 /* FIXME: Cache these */
2594                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2595                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2596
2597                 sig = ctor_sig;
2598         }
2599
2600         context_used = mini_method_check_context_used (cfg, method);
2601
2602 #ifndef DISABLE_REMOTING
2603         might_be_remote = this_ins && sig->hasthis &&
2604                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2605                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2606
2607         if (might_be_remote && context_used) {
2608                 MonoInst *addr;
2609
2610                 g_assert (cfg->gshared);
2611
2612                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2613
2614                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2615         }
2616 #endif
2617
2618         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2619                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2620
2621         need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass);
2622
2623         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2624
2625 #ifndef DISABLE_REMOTING
2626         if (might_be_remote)
2627                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2628         else
2629 #endif
2630                 call->method = method;
2631         call->inst.flags |= MONO_INST_HAS_METHOD;
2632         call->inst.inst_left = this_ins;
2633         call->tail_call = tail;
2634
2635         if (virtual_) {
2636                 int vtable_reg, slot_reg, this_reg;
2637                 int offset;
2638
2639                 this_reg = this_ins->dreg;
2640
2641                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2642                         MonoInst *dummy_use;
2643
2644                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2645
2646                         /* Make a call to delegate->invoke_impl */
2647                         call->inst.inst_basereg = this_reg;
2648                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2649                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2650
2651                         /* We must emit a dummy use here because the delegate trampoline will
2652                         replace the 'this' argument with the delegate target making this activation
2653                         no longer a root for the delegate.
2654                         This is an issue for delegates that target collectible code such as dynamic
2655                         methods of GC'able assemblies.
2656
2657                         For a test case look into #667921.
2658
2659                         FIXME: a dummy use is not the best way to do it as the local register allocator
2660                         will put it on a caller save register and spil it around the call. 
2661                         Ideally, we would either put it on a callee save register or only do the store part.  
2662                          */
2663                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2664
2665                         return (MonoInst*)call;
2666                 }
2667
2668                 if ((!cfg->compile_aot || enable_for_aot) && 
2669                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2670                          (MONO_METHOD_IS_FINAL (method) &&
2671                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2672                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2673                         /* 
2674                          * the method is not virtual, we just need to ensure this is not null
2675                          * and then we can call the method directly.
2676                          */
2677 #ifndef DISABLE_REMOTING
2678                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2679                                 /* 
2680                                  * The check above ensures method is not gshared, this is needed since
2681                                  * gshared methods can't have wrappers.
2682                                  */
2683                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2684                         }
2685 #endif
2686
2687                         if (!method->string_ctor)
2688                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2689
2690                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2691                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2692                         /*
2693                          * the method is virtual, but we can statically dispatch since either
2694                          * it's class or the method itself are sealed.
2695                          * But first we need to ensure it's not a null reference.
2696                          */
2697                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2698
2699                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2700                 } else if (call_target) {
2701                         vtable_reg = alloc_preg (cfg);
2702                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2703
2704                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2705                         call->inst.sreg1 = call_target->dreg;
2706                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2707                 } else {
2708                         vtable_reg = alloc_preg (cfg);
2709                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2710                         if (mono_class_is_interface (method->klass)) {
2711                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2712                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2713                                 slot_reg = vtable_reg;
2714                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2715                         } else {
2716                                 slot_reg = vtable_reg;
2717                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2718                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2719                                 if (imt_arg) {
2720                                         g_assert (mono_method_signature (method)->generic_param_count);
2721                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2722                                 }
2723                         }
2724
2725                         call->inst.sreg1 = slot_reg;
2726                         call->inst.inst_offset = offset;
2727                         call->is_virtual = TRUE;
2728                 }
2729         }
2730
2731         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2732
2733         if (rgctx_arg)
2734                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2735
2736         return (MonoInst*)call;
2737 }
2738
2739 MonoInst*
2740 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2741 {
2742         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2743 }
2744
2745 MonoInst*
2746 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2747                                            MonoInst **args)
2748 {
2749         MonoCallInst *call;
2750
2751         g_assert (sig);
2752
2753         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2754         call->fptr = func;
2755
2756         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2757
2758         return (MonoInst*)call;
2759 }
2760
2761 MonoInst*
2762 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2763 {
2764         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2765
2766         g_assert (info);
2767
2768         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2769 }
2770
2771 /*
2772  * mono_emit_abs_call:
2773  *
2774  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2775  */
2776 inline static MonoInst*
2777 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2778                                         MonoMethodSignature *sig, MonoInst **args)
2779 {
2780         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2781         MonoInst *ins;
2782
2783         /* 
2784          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2785          * handle it.
2786          */
2787         if (cfg->abs_patches == NULL)
2788                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2789         g_hash_table_insert (cfg->abs_patches, ji, ji);
2790         ins = mono_emit_native_call (cfg, ji, sig, args);
2791         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2792         return ins;
2793 }
2794
2795 static MonoMethodSignature*
2796 sig_to_rgctx_sig (MonoMethodSignature *sig)
2797 {
2798         // FIXME: memory allocation
2799         MonoMethodSignature *res;
2800         int i;
2801
2802         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2803         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2804         res->param_count = sig->param_count + 1;
2805         for (i = 0; i < sig->param_count; ++i)
2806                 res->params [i] = sig->params [i];
2807         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
2808         return res;
2809 }
2810
2811 /* Make an indirect call to FSIG passing an additional argument */
2812 static MonoInst*
2813 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
2814 {
2815         MonoMethodSignature *csig;
2816         MonoInst *args_buf [16];
2817         MonoInst **args;
2818         int i, pindex, tmp_reg;
2819
2820         /* Make a call with an rgctx/extra arg */
2821         if (fsig->param_count + 2 < 16)
2822                 args = args_buf;
2823         else
2824                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
2825         pindex = 0;
2826         if (fsig->hasthis)
2827                 args [pindex ++] = orig_args [0];
2828         for (i = 0; i < fsig->param_count; ++i)
2829                 args [pindex ++] = orig_args [fsig->hasthis + i];
2830         tmp_reg = alloc_preg (cfg);
2831         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
2832         csig = sig_to_rgctx_sig (fsig);
2833         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
2834 }
2835
2836 /* Emit an indirect call to the function descriptor ADDR */
2837 static MonoInst*
2838 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
2839 {
2840         int addr_reg, arg_reg;
2841         MonoInst *call_target;
2842
2843         g_assert (cfg->llvm_only);
2844
2845         /*
2846          * addr points to a <addr, arg> pair, load both of them, and
2847          * make a call to addr, passing arg as an extra arg.
2848          */
2849         addr_reg = alloc_preg (cfg);
2850         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
2851         arg_reg = alloc_preg (cfg);
2852         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
2853
2854         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
2855 }
2856
2857 static gboolean
2858 direct_icalls_enabled (MonoCompile *cfg)
2859 {
2860         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
2861 #ifdef TARGET_AMD64
2862         if (cfg->compile_llvm && !cfg->llvm_only)
2863                 return FALSE;
2864 #endif
2865         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
2866                 return FALSE;
2867         return TRUE;
2868 }
2869
2870 MonoInst*
2871 mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
2872 {
2873         /*
2874          * Call the jit icall without a wrapper if possible.
2875          * The wrapper is needed for the following reasons:
2876          * - to handle exceptions thrown using mono_raise_exceptions () from the
2877          *   icall function. The EH code needs the lmf frame pushed by the
2878          *   wrapper to be able to unwind back to managed code.
2879          * - to be able to do stack walks for asynchronously suspended
2880          *   threads when debugging.
2881          */
2882         if (info->no_raise && direct_icalls_enabled (cfg)) {
2883                 char *name;
2884                 int costs;
2885
2886                 if (!info->wrapper_method) {
2887                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
2888                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
2889                         g_free (name);
2890                         mono_memory_barrier ();
2891                 }
2892
2893                 /*
2894                  * Inline the wrapper method, which is basically a call to the C icall, and
2895                  * an exception check.
2896                  */
2897                 costs = inline_method (cfg, info->wrapper_method, NULL,
2898                                                            args, NULL, il_offset, TRUE);
2899                 g_assert (costs > 0);
2900                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
2901
2902                 return args [0];
2903         } else {
2904                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2905         }
2906 }
2907  
2908 static MonoInst*
2909 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2910 {
2911         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2912                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2913                         int widen_op = -1;
2914
2915                         /* 
2916                          * Native code might return non register sized integers 
2917                          * without initializing the upper bits.
2918                          */
2919                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2920                         case OP_LOADI1_MEMBASE:
2921                                 widen_op = OP_ICONV_TO_I1;
2922                                 break;
2923                         case OP_LOADU1_MEMBASE:
2924                                 widen_op = OP_ICONV_TO_U1;
2925                                 break;
2926                         case OP_LOADI2_MEMBASE:
2927                                 widen_op = OP_ICONV_TO_I2;
2928                                 break;
2929                         case OP_LOADU2_MEMBASE:
2930                                 widen_op = OP_ICONV_TO_U2;
2931                                 break;
2932                         default:
2933                                 break;
2934                         }
2935
2936                         if (widen_op != -1) {
2937                                 int dreg = alloc_preg (cfg);
2938                                 MonoInst *widen;
2939
2940                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2941                                 widen->type = ins->type;
2942                                 ins = widen;
2943                         }
2944                 }
2945         }
2946
2947         return ins;
2948 }
2949
2950
2951 static void
2952 emit_method_access_failure (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
2953 {
2954         MonoInst *args [16];
2955
2956         args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (caller), caller, MONO_RGCTX_INFO_METHOD);
2957         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (callee), callee, MONO_RGCTX_INFO_METHOD);
2958
2959         mono_emit_jit_icall (cfg, mono_throw_method_access, args);
2960 }
2961
2962 static MonoMethod*
2963 get_memcpy_method (void)
2964 {
2965         static MonoMethod *memcpy_method = NULL;
2966         if (!memcpy_method) {
2967                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2968                 if (!memcpy_method)
2969                         g_error ("Old corlib found. Install a new one");
2970         }
2971         return memcpy_method;
2972 }
2973
2974 static void
2975 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
2976 {
2977         MonoClassField *field;
2978         gpointer iter = NULL;
2979
2980         while ((field = mono_class_get_fields (klass, &iter))) {
2981                 int foffset;
2982
2983                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2984                         continue;
2985                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2986                 if (mini_type_is_reference (mono_field_get_type (field))) {
2987                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2988                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2989                 } else {
2990                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2991                         if (field_class->has_references)
2992                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
2993                 }
2994         }
2995 }
2996
2997 static void
2998 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
2999 {
3000         int card_table_shift_bits;
3001         gpointer card_table_mask;
3002         guint8 *card_table;
3003         MonoInst *dummy_use;
3004         int nursery_shift_bits;
3005         size_t nursery_size;
3006
3007         if (!cfg->gen_write_barriers)
3008                 return;
3009
3010         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3011
3012         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3013
3014         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3015                 MonoInst *wbarrier;
3016
3017                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3018                 wbarrier->sreg1 = ptr->dreg;
3019                 wbarrier->sreg2 = value->dreg;
3020                 MONO_ADD_INS (cfg->cbb, wbarrier);
3021         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3022                 int offset_reg = alloc_preg (cfg);
3023                 int card_reg;
3024                 MonoInst *ins;
3025
3026                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3027                 if (card_table_mask)
3028                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3029
3030                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3031                  * IMM's larger than 32bits.
3032                  */
3033                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3034                 card_reg = ins->dreg;
3035
3036                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3037                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3038         } else {
3039                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3040                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3041         }
3042
3043         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3044 }
3045
3046 static gboolean
3047 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3048 {
3049         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3050         unsigned need_wb = 0;
3051
3052         if (align == 0)
3053                 align = 4;
3054
3055         /*types with references can't have alignment smaller than sizeof(void*) */
3056         if (align < SIZEOF_VOID_P)
3057                 return FALSE;
3058
3059         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3060         if (size > 32 * SIZEOF_VOID_P)
3061                 return FALSE;
3062
3063         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3064
3065         /* We don't unroll more than 5 stores to avoid code bloat. */
3066         if (size > 5 * SIZEOF_VOID_P) {
3067                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3068                 size += (SIZEOF_VOID_P - 1);
3069                 size &= ~(SIZEOF_VOID_P - 1);
3070
3071                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3072                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3073                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3074                 return TRUE;
3075         }
3076
3077         destreg = iargs [0]->dreg;
3078         srcreg = iargs [1]->dreg;
3079         offset = 0;
3080
3081         dest_ptr_reg = alloc_preg (cfg);
3082         tmp_reg = alloc_preg (cfg);
3083
3084         /*tmp = dreg*/
3085         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3086
3087         while (size >= SIZEOF_VOID_P) {
3088                 MonoInst *load_inst;
3089                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3090                 load_inst->dreg = tmp_reg;
3091                 load_inst->inst_basereg = srcreg;
3092                 load_inst->inst_offset = offset;
3093                 MONO_ADD_INS (cfg->cbb, load_inst);
3094
3095                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3096
3097                 if (need_wb & 0x1)
3098                         emit_write_barrier (cfg, iargs [0], load_inst);
3099
3100                 offset += SIZEOF_VOID_P;
3101                 size -= SIZEOF_VOID_P;
3102                 need_wb >>= 1;
3103
3104                 /*tmp += sizeof (void*)*/
3105                 if (size >= SIZEOF_VOID_P) {
3106                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3107                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3108                 }
3109         }
3110
3111         /* Those cannot be references since size < sizeof (void*) */
3112         while (size >= 4) {
3113                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3114                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3115                 offset += 4;
3116                 size -= 4;
3117         }
3118
3119         while (size >= 2) {
3120                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3121                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3122                 offset += 2;
3123                 size -= 2;
3124         }
3125
3126         while (size >= 1) {
3127                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3128                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3129                 offset += 1;
3130                 size -= 1;
3131         }
3132
3133         return TRUE;
3134 }
3135
3136 /*
3137  * Emit code to copy a valuetype of type @klass whose address is stored in
3138  * @src->dreg to memory whose address is stored at @dest->dreg.
3139  */
3140 void
3141 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3142 {
3143         MonoInst *iargs [4];
3144         int n;
3145         guint32 align = 0;
3146         MonoMethod *memcpy_method;
3147         MonoInst *size_ins = NULL;
3148         MonoInst *memcpy_ins = NULL;
3149
3150         g_assert (klass);
3151         if (cfg->gshared)
3152                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3153
3154         /*
3155          * This check breaks with spilled vars... need to handle it during verification anyway.
3156          * g_assert (klass && klass == src->klass && klass == dest->klass);
3157          */
3158
3159         if (mini_is_gsharedvt_klass (klass)) {
3160                 g_assert (!native);
3161                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3162                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3163         }
3164
3165         if (native)
3166                 n = mono_class_native_size (klass, &align);
3167         else
3168                 n = mono_class_value_size (klass, &align);
3169
3170         /* if native is true there should be no references in the struct */
3171         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3172                 /* Avoid barriers when storing to the stack */
3173                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3174                           (dest->opcode == OP_LDADDR))) {
3175                         int context_used;
3176
3177                         iargs [0] = dest;
3178                         iargs [1] = src;
3179
3180                         context_used = mini_class_check_context_used (cfg, klass);
3181
3182                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3183                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3184                                 return;
3185                         } else if (context_used) {
3186                                 iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3187                         }  else {
3188                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3189                                 if (!cfg->compile_aot)
3190                                         mono_class_compute_gc_descriptor (klass);
3191                         }
3192
3193                         if (size_ins)
3194                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3195                         else
3196                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3197                         return;
3198                 }
3199         }
3200
3201         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3202                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3203                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3204         } else {
3205                 iargs [0] = dest;
3206                 iargs [1] = src;
3207                 if (size_ins)
3208                         iargs [2] = size_ins;
3209                 else
3210                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3211                 
3212                 memcpy_method = get_memcpy_method ();
3213                 if (memcpy_ins)
3214                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3215                 else
3216                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3217         }
3218 }
3219
3220 static MonoMethod*
3221 get_memset_method (void)
3222 {
3223         static MonoMethod *memset_method = NULL;
3224         if (!memset_method) {
3225                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3226                 if (!memset_method)
3227                         g_error ("Old corlib found. Install a new one");
3228         }
3229         return memset_method;
3230 }
3231
3232 void
3233 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3234 {
3235         MonoInst *iargs [3];
3236         int n;
3237         guint32 align;
3238         MonoMethod *memset_method;
3239         MonoInst *size_ins = NULL;
3240         MonoInst *bzero_ins = NULL;
3241         static MonoMethod *bzero_method;
3242
3243         /* FIXME: Optimize this for the case when dest is an LDADDR */
3244         mono_class_init (klass);
3245         if (mini_is_gsharedvt_klass (klass)) {
3246                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3247                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3248                 if (!bzero_method)
3249                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3250                 g_assert (bzero_method);
3251                 iargs [0] = dest;
3252                 iargs [1] = size_ins;
3253                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3254                 return;
3255         }
3256
3257         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3258
3259         n = mono_class_value_size (klass, &align);
3260
3261         if (n <= sizeof (gpointer) * 8) {
3262                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3263         }
3264         else {
3265                 memset_method = get_memset_method ();
3266                 iargs [0] = dest;
3267                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3268                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3269                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3270         }
3271 }
3272
3273 /*
3274  * emit_get_rgctx:
3275  *
3276  *   Emit IR to return either the this pointer for instance method,
3277  * or the mrgctx for static methods.
3278  */
3279 static MonoInst*
3280 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3281 {
3282         MonoInst *this_ins = NULL;
3283
3284         g_assert (cfg->gshared);
3285
3286         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3287                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3288                 !method->klass->valuetype)
3289                 EMIT_NEW_VARLOAD (cfg, this_ins, cfg->this_arg, &mono_defaults.object_class->byval_arg);
3290
3291         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3292                 MonoInst *mrgctx_loc, *mrgctx_var;
3293
3294                 g_assert (!this_ins);
3295                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3296
3297                 mrgctx_loc = mono_get_vtable_var (cfg);
3298                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3299
3300                 return mrgctx_var;
3301         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3302                 MonoInst *vtable_loc, *vtable_var;
3303
3304                 g_assert (!this_ins);
3305
3306                 vtable_loc = mono_get_vtable_var (cfg);
3307                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3308
3309                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3310                         MonoInst *mrgctx_var = vtable_var;
3311                         int vtable_reg;
3312
3313                         vtable_reg = alloc_preg (cfg);
3314                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3315                         vtable_var->type = STACK_PTR;
3316                 }
3317
3318                 return vtable_var;
3319         } else {
3320                 MonoInst *ins;
3321                 int vtable_reg;
3322         
3323                 vtable_reg = alloc_preg (cfg);
3324                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3325                 return ins;
3326         }
3327 }
3328
3329 static MonoJumpInfoRgctxEntry *
3330 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3331 {
3332         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3333         res->method = method;
3334         res->in_mrgctx = in_mrgctx;
3335         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3336         res->data->type = patch_type;
3337         res->data->data.target = patch_data;
3338         res->info_type = info_type;
3339
3340         return res;
3341 }
3342
3343 static inline MonoInst*
3344 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3345 {
3346         MonoInst *args [16];
3347         MonoInst *call;
3348
3349         // FIXME: No fastpath since the slot is not a compile time constant
3350         args [0] = rgctx;
3351         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3352         if (entry->in_mrgctx)
3353                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3354         else
3355                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3356         return call;
3357 #if 0
3358         /*
3359          * FIXME: This can be called during decompose, which is a problem since it creates
3360          * new bblocks.
3361          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3362          */
3363         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3364         gboolean mrgctx;
3365         MonoBasicBlock *is_null_bb, *end_bb;
3366         MonoInst *res, *ins, *call;
3367         MonoInst *args[16];
3368
3369         slot = mini_get_rgctx_entry_slot (entry);
3370
3371         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3372         index = MONO_RGCTX_SLOT_INDEX (slot);
3373         if (mrgctx)
3374                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3375         for (depth = 0; ; ++depth) {
3376                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3377
3378                 if (index < size - 1)
3379                         break;
3380                 index -= size - 1;
3381         }
3382
3383         NEW_BBLOCK (cfg, end_bb);
3384         NEW_BBLOCK (cfg, is_null_bb);
3385
3386         if (mrgctx) {
3387                 rgctx_reg = rgctx->dreg;
3388         } else {
3389                 rgctx_reg = alloc_preg (cfg);
3390
3391                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3392                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3393                 NEW_BBLOCK (cfg, is_null_bb);
3394
3395                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3396                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3397         }
3398
3399         for (i = 0; i < depth; ++i) {
3400                 int array_reg = alloc_preg (cfg);
3401
3402                 /* load ptr to next array */
3403                 if (mrgctx && i == 0)
3404                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3405                 else
3406                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3407                 rgctx_reg = array_reg;
3408                 /* is the ptr null? */
3409                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3410                 /* if yes, jump to actual trampoline */
3411                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3412         }
3413
3414         /* fetch slot */
3415         val_reg = alloc_preg (cfg);
3416         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3417         /* is the slot null? */
3418         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3419         /* if yes, jump to actual trampoline */
3420         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3421
3422         /* Fastpath */
3423         res_reg = alloc_preg (cfg);
3424         MONO_INST_NEW (cfg, ins, OP_MOVE);
3425         ins->dreg = res_reg;
3426         ins->sreg1 = val_reg;
3427         MONO_ADD_INS (cfg->cbb, ins);
3428         res = ins;
3429         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3430
3431         /* Slowpath */
3432         MONO_START_BB (cfg, is_null_bb);
3433         args [0] = rgctx;
3434         EMIT_NEW_ICONST (cfg, args [1], index);
3435         if (mrgctx)
3436                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3437         else
3438                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3439         MONO_INST_NEW (cfg, ins, OP_MOVE);
3440         ins->dreg = res_reg;
3441         ins->sreg1 = call->dreg;
3442         MONO_ADD_INS (cfg->cbb, ins);
3443         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3444
3445         MONO_START_BB (cfg, end_bb);
3446
3447         return res;
3448 #endif
3449 }
3450
3451 /*
3452  * emit_rgctx_fetch:
3453  *
3454  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3455  * given by RGCTX.
3456  */
3457 static inline MonoInst*
3458 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3459 {
3460         if (cfg->llvm_only)
3461                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3462         else
3463                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3464 }
3465
3466 MonoInst*
3467 mini_emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3468                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3469 {
3470         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);
3471         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3472
3473         return emit_rgctx_fetch (cfg, rgctx, entry);
3474 }
3475
3476 static MonoInst*
3477 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3478                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3479 {
3480         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);
3481         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3482
3483         return emit_rgctx_fetch (cfg, rgctx, entry);
3484 }
3485
3486 static MonoInst*
3487 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3488                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3489 {
3490         MonoJumpInfoGSharedVtCall *call_info;
3491         MonoJumpInfoRgctxEntry *entry;
3492         MonoInst *rgctx;
3493
3494         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3495         call_info->sig = sig;
3496         call_info->method = cmethod;
3497
3498         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);
3499         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3500
3501         return emit_rgctx_fetch (cfg, rgctx, entry);
3502 }
3503
3504 /*
3505  * emit_get_rgctx_virt_method:
3506  *
3507  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3508  */
3509 static MonoInst*
3510 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3511                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3512 {
3513         MonoJumpInfoVirtMethod *info;
3514         MonoJumpInfoRgctxEntry *entry;
3515         MonoInst *rgctx;
3516
3517         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3518         info->klass = klass;
3519         info->method = virt_method;
3520
3521         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);
3522         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3523
3524         return emit_rgctx_fetch (cfg, rgctx, entry);
3525 }
3526
3527 static MonoInst*
3528 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3529                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3530 {
3531         MonoJumpInfoRgctxEntry *entry;
3532         MonoInst *rgctx;
3533
3534         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);
3535         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3536
3537         return emit_rgctx_fetch (cfg, rgctx, entry);
3538 }
3539
3540 /*
3541  * emit_get_rgctx_method:
3542  *
3543  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3544  * normal constants, else emit a load from the rgctx.
3545  */
3546 static MonoInst*
3547 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3548                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3549 {
3550         if (!context_used) {
3551                 MonoInst *ins;
3552
3553                 switch (rgctx_type) {
3554                 case MONO_RGCTX_INFO_METHOD:
3555                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3556                         return ins;
3557                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3558                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3559                         return ins;
3560                 default:
3561                         g_assert_not_reached ();
3562                 }
3563         } else {
3564                 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);
3565                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3566
3567                 return emit_rgctx_fetch (cfg, rgctx, entry);
3568         }
3569 }
3570
3571 static MonoInst*
3572 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3573                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3574 {
3575         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);
3576         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3577
3578         return emit_rgctx_fetch (cfg, rgctx, entry);
3579 }
3580
3581 static int
3582 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3583 {
3584         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3585         MonoRuntimeGenericContextInfoTemplate *template_;
3586         int i, idx;
3587
3588         g_assert (info);
3589
3590         for (i = 0; i < info->num_entries; ++i) {
3591                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3592
3593                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3594                         return i;
3595         }
3596
3597         if (info->num_entries == info->count_entries) {
3598                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3599                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3600
3601                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3602
3603                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3604                 info->entries = new_entries;
3605                 info->count_entries = new_count_entries;
3606         }
3607
3608         idx = info->num_entries;
3609         template_ = &info->entries [idx];
3610         template_->info_type = rgctx_type;
3611         template_->data = data;
3612
3613         info->num_entries ++;
3614
3615         return idx;
3616 }
3617
3618 /*
3619  * emit_get_gsharedvt_info:
3620  *
3621  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3622  */
3623 static MonoInst*
3624 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3625 {
3626         MonoInst *ins;
3627         int idx, dreg;
3628
3629         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3630         /* Load info->entries [idx] */
3631         dreg = alloc_preg (cfg);
3632         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3633
3634         return ins;
3635 }
3636
3637 static MonoInst*
3638 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3639 {
3640         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3641 }
3642
3643 /*
3644  * On return the caller must check @klass for load errors.
3645  */
3646 static void
3647 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3648 {
3649         MonoInst *vtable_arg;
3650         int context_used;
3651
3652         context_used = mini_class_check_context_used (cfg, klass);
3653
3654         if (context_used) {
3655                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
3656                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3657         } else {
3658                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3659
3660                 if (!vtable)
3661                         return;
3662                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3663         }
3664
3665         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3666                 MonoInst *ins;
3667
3668                 /*
3669                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3670                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3671                  */
3672                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3673                 ins->sreg1 = vtable_arg->dreg;
3674                 MONO_ADD_INS (cfg->cbb, ins);
3675         } else {
3676                 int inited_reg;
3677                 MonoBasicBlock *inited_bb;
3678                 MonoInst *args [16];
3679
3680                 inited_reg = alloc_ireg (cfg);
3681
3682                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, inited_reg, vtable_arg->dreg, MONO_STRUCT_OFFSET (MonoVTable, initialized));
3683
3684                 NEW_BBLOCK (cfg, inited_bb);
3685
3686                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3687                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3688
3689                 args [0] = vtable_arg;
3690                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3691
3692                 MONO_START_BB (cfg, inited_bb);
3693         }
3694 }
3695
3696 static void
3697 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3698 {
3699         MonoInst *ins;
3700
3701         if (cfg->gen_seq_points && cfg->method == method) {
3702                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3703                 if (nonempty_stack)
3704                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3705                 MONO_ADD_INS (cfg->cbb, ins);
3706         }
3707 }
3708
3709 void
3710 mini_save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3711 {
3712         if (mini_get_debug_options ()->better_cast_details) {
3713                 int vtable_reg = alloc_preg (cfg);
3714                 int klass_reg = alloc_preg (cfg);
3715                 MonoBasicBlock *is_null_bb = NULL;
3716                 MonoInst *tls_get;
3717                 int to_klass_reg, context_used;
3718
3719                 if (null_check) {
3720                         NEW_BBLOCK (cfg, is_null_bb);
3721
3722                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3723                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3724                 }
3725
3726                 tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
3727                 if (!tls_get) {
3728                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3729                         exit (1);
3730                 }
3731
3732                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3733                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3734
3735                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3736
3737                 context_used = mini_class_check_context_used (cfg, klass);
3738                 if (context_used) {
3739                         MonoInst *class_ins;
3740
3741                         class_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3742                         to_klass_reg = class_ins->dreg;
3743                 } else {
3744                         to_klass_reg = alloc_preg (cfg);
3745                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3746                 }
3747                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3748
3749                 if (null_check)
3750                         MONO_START_BB (cfg, is_null_bb);
3751         }
3752 }
3753
3754 void
3755 mini_reset_cast_details (MonoCompile *cfg)
3756 {
3757         /* Reset the variables holding the cast details */
3758         if (mini_get_debug_options ()->better_cast_details) {
3759                 MonoInst *tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
3760                 /* It is enough to reset the from field */
3761                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3762         }
3763 }
3764
3765 /*
3766  * On return the caller must check @array_class for load errors
3767  */
3768 static void
3769 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3770 {
3771         int vtable_reg = alloc_preg (cfg);
3772         int context_used;
3773
3774         context_used = mini_class_check_context_used (cfg, array_class);
3775
3776         mini_save_cast_details (cfg, array_class, obj->dreg, FALSE);
3777
3778         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3779
3780         if (cfg->opt & MONO_OPT_SHARED) {
3781                 int class_reg = alloc_preg (cfg);
3782                 MonoInst *ins;
3783
3784                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3785                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3786                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3787         } else if (context_used) {
3788                 MonoInst *vtable_ins;
3789
3790                 vtable_ins = mini_emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3791                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3792         } else {
3793                 if (cfg->compile_aot) {
3794                         int vt_reg;
3795                         MonoVTable *vtable;
3796
3797                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3798                                 return;
3799                         vt_reg = alloc_preg (cfg);
3800                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3801                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3802                 } else {
3803                         MonoVTable *vtable;
3804                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3805                                 return;
3806                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3807                 }
3808         }
3809         
3810         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3811
3812         mini_reset_cast_details (cfg);
3813 }
3814
3815 /**
3816  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3817  * generic code is generated.
3818  */
3819 static MonoInst*
3820 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3821 {
3822         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3823
3824         if (context_used) {
3825                 MonoInst *rgctx, *addr;
3826
3827                 /* FIXME: What if the class is shared?  We might not
3828                    have to get the address of the method from the
3829                    RGCTX. */
3830                 addr = emit_get_rgctx_method (cfg, context_used, method,
3831                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3832                 if (cfg->llvm_only) {
3833                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
3834                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
3835                 } else {
3836                         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3837
3838                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3839                 }
3840         } else {
3841                 gboolean pass_vtable, pass_mrgctx;
3842                 MonoInst *rgctx_arg = NULL;
3843
3844                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3845                 g_assert (!pass_mrgctx);
3846
3847                 if (pass_vtable) {
3848                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3849
3850                         g_assert (vtable);
3851                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3852                 }
3853
3854                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3855         }
3856 }
3857
3858 static MonoInst*
3859 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3860 {
3861         MonoInst *add;
3862         int obj_reg;
3863         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3864         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3865         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3866         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3867
3868         obj_reg = sp [0]->dreg;
3869         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3870         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3871
3872         /* FIXME: generics */
3873         g_assert (klass->rank == 0);
3874                         
3875         // Check rank == 0
3876         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3877         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3878
3879         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3880         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3881
3882         if (context_used) {
3883                 MonoInst *element_class;
3884
3885                 /* This assertion is from the unboxcast insn */
3886                 g_assert (klass->rank == 0);
3887
3888                 element_class = mini_emit_get_rgctx_klass (cfg, context_used,
3889                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
3890
3891                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3892                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3893         } else {
3894                 mini_save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
3895                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3896                 mini_reset_cast_details (cfg);
3897         }
3898
3899         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3900         MONO_ADD_INS (cfg->cbb, add);
3901         add->type = STACK_MP;
3902         add->klass = klass;
3903
3904         return add;
3905 }
3906
3907 static MonoInst*
3908 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
3909 {
3910         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3911         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3912         MonoInst *ins;
3913         int dreg, addr_reg;
3914
3915         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3916
3917         /* obj */
3918         args [0] = obj;
3919
3920         /* klass */
3921         args [1] = klass_inst;
3922
3923         /* CASTCLASS */
3924         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3925
3926         NEW_BBLOCK (cfg, is_ref_bb);
3927         NEW_BBLOCK (cfg, is_nullable_bb);
3928         NEW_BBLOCK (cfg, end_bb);
3929         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3930         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
3931         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3932
3933         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
3934         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3935
3936         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3937         addr_reg = alloc_dreg (cfg, STACK_MP);
3938
3939         /* Non-ref case */
3940         /* UNBOX */
3941         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3942         MONO_ADD_INS (cfg->cbb, addr);
3943
3944         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3945
3946         /* Ref case */
3947         MONO_START_BB (cfg, is_ref_bb);
3948
3949         /* Save the ref to a temporary */
3950         dreg = alloc_ireg (cfg);
3951         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3952         addr->dreg = addr_reg;
3953         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3954         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3955
3956         /* Nullable case */
3957         MONO_START_BB (cfg, is_nullable_bb);
3958
3959         {
3960                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3961                 MonoInst *unbox_call;
3962                 MonoMethodSignature *unbox_sig;
3963
3964                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3965                 unbox_sig->ret = &klass->byval_arg;
3966                 unbox_sig->param_count = 1;
3967                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3968
3969                 if (cfg->llvm_only)
3970                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
3971                 else
3972                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3973
3974                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3975                 addr->dreg = addr_reg;
3976         }
3977
3978         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3979
3980         /* End */
3981         MONO_START_BB (cfg, end_bb);
3982
3983         /* LDOBJ */
3984         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3985
3986         return ins;
3987 }
3988
3989 /*
3990  * Returns NULL and set the cfg exception on error.
3991  */
3992 static MonoInst*
3993 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3994 {
3995         MonoInst *iargs [2];
3996         void *alloc_ftn;
3997
3998         if (context_used) {
3999                 MonoInst *data;
4000                 MonoRgctxInfoType rgctx_info;
4001                 MonoInst *iargs [2];
4002                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4003
4004                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4005
4006                 if (cfg->opt & MONO_OPT_SHARED)
4007                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4008                 else
4009                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4010                 data = mini_emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4011
4012                 if (cfg->opt & MONO_OPT_SHARED) {
4013                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4014                         iargs [1] = data;
4015                         alloc_ftn = ves_icall_object_new;
4016                 } else {
4017                         iargs [0] = data;
4018                         alloc_ftn = ves_icall_object_new_specific;
4019                 }
4020
4021                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4022                         if (known_instance_size) {
4023                                 int size = mono_class_instance_size (klass);
4024                                 if (size < sizeof (MonoObject))
4025                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4026
4027                                 EMIT_NEW_ICONST (cfg, iargs [1], size);
4028                         }
4029                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4030                 }
4031
4032                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4033         }
4034
4035         if (cfg->opt & MONO_OPT_SHARED) {
4036                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4037                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4038
4039                 alloc_ftn = ves_icall_object_new;
4040         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !mono_class_is_ginst (klass)) {
4041                 /* This happens often in argument checking code, eg. throw new FooException... */
4042                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4043                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4044                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4045         } else {
4046                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4047                 MonoMethod *managed_alloc = NULL;
4048                 gboolean pass_lw;
4049
4050                 if (!vtable) {
4051                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4052                         cfg->exception_ptr = klass;
4053                         return NULL;
4054                 }
4055
4056                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4057
4058                 if (managed_alloc) {
4059                         int size = mono_class_instance_size (klass);
4060                         if (size < sizeof (MonoObject))
4061                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4062
4063                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4064                         EMIT_NEW_ICONST (cfg, iargs [1], size);
4065                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4066                 }
4067                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4068                 if (pass_lw) {
4069                         guint32 lw = vtable->klass->instance_size;
4070                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4071                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4072                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4073                 }
4074                 else {
4075                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4076                 }
4077         }
4078
4079         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4080 }
4081         
4082 /*
4083  * Returns NULL and set the cfg exception on error.
4084  */     
4085 static MonoInst*
4086 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4087 {
4088         MonoInst *alloc, *ins;
4089
4090         if (mono_class_is_nullable (klass)) {
4091                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4092
4093                 if (context_used) {
4094                         if (cfg->llvm_only && cfg->gsharedvt) {
4095                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4096                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4097                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4098                         } else {
4099                                 /* FIXME: What if the class is shared?  We might not
4100                                    have to get the method address from the RGCTX. */
4101                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4102                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4103                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
4104
4105                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4106                         }
4107                 } else {
4108                         gboolean pass_vtable, pass_mrgctx;
4109                         MonoInst *rgctx_arg = NULL;
4110
4111                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4112                         g_assert (!pass_mrgctx);
4113
4114                         if (pass_vtable) {
4115                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4116
4117                                 g_assert (vtable);
4118                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4119                         }
4120
4121                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4122                 }
4123         }
4124
4125         if (mini_is_gsharedvt_klass (klass)) {
4126                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4127                 MonoInst *res, *is_ref, *src_var, *addr;
4128                 int dreg;
4129
4130                 dreg = alloc_ireg (cfg);
4131
4132                 NEW_BBLOCK (cfg, is_ref_bb);
4133                 NEW_BBLOCK (cfg, is_nullable_bb);
4134                 NEW_BBLOCK (cfg, end_bb);
4135                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4136                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4137                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4138
4139                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4140                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4141
4142                 /* Non-ref case */
4143                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4144                 if (!alloc)
4145                         return NULL;
4146                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4147                 ins->opcode = OP_STOREV_MEMBASE;
4148
4149                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4150                 res->type = STACK_OBJ;
4151                 res->klass = klass;
4152                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4153                 
4154                 /* Ref case */
4155                 MONO_START_BB (cfg, is_ref_bb);
4156
4157                 /* val is a vtype, so has to load the value manually */
4158                 src_var = get_vreg_to_inst (cfg, val->dreg);
4159                 if (!src_var)
4160                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4161                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4162                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4163                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4164
4165                 /* Nullable case */
4166                 MONO_START_BB (cfg, is_nullable_bb);
4167
4168                 {
4169                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4170                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4171                         MonoInst *box_call;
4172                         MonoMethodSignature *box_sig;
4173
4174                         /*
4175                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4176                          * construct that method at JIT time, so have to do things by hand.
4177                          */
4178                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4179                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4180                         box_sig->param_count = 1;
4181                         box_sig->params [0] = &klass->byval_arg;
4182
4183                         if (cfg->llvm_only)
4184                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4185                         else
4186                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4187                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4188                         res->type = STACK_OBJ;
4189                         res->klass = klass;
4190                 }
4191
4192                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4193
4194                 MONO_START_BB (cfg, end_bb);
4195
4196                 return res;
4197         } else {
4198                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4199                 if (!alloc)
4200                         return NULL;
4201
4202                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4203                 return alloc;
4204         }
4205 }
4206
4207 static GHashTable* direct_icall_type_hash;
4208
4209 static gboolean
4210 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4211 {
4212         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4213         if (!direct_icalls_enabled (cfg))
4214                 return FALSE;
4215
4216         /*
4217          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4218          * Whitelist a few icalls for now.
4219          */
4220         if (!direct_icall_type_hash) {
4221                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4222
4223                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4224                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4225                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4226                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4227                 mono_memory_barrier ();
4228                 direct_icall_type_hash = h;
4229         }
4230
4231         if (cmethod->klass == mono_defaults.math_class)
4232                 return TRUE;
4233         /* No locking needed */
4234         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4235                 return TRUE;
4236         return FALSE;
4237 }
4238
4239 static gboolean
4240 method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
4241 {
4242         if (cmethod->klass == mono_defaults.systemtype_class) {
4243                 if (!strcmp (cmethod->name, "GetType"))
4244                         return TRUE;
4245         }
4246         return FALSE;
4247 }
4248
4249 static G_GNUC_UNUSED MonoInst*
4250 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4251 {
4252         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4253         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4254         gboolean is_i4;
4255
4256         switch (enum_type->type) {
4257         case MONO_TYPE_I8:
4258         case MONO_TYPE_U8:
4259 #if SIZEOF_REGISTER == 8
4260         case MONO_TYPE_I:
4261         case MONO_TYPE_U:
4262 #endif
4263                 is_i4 = FALSE;
4264                 break;
4265         default:
4266                 is_i4 = TRUE;
4267                 break;
4268         }
4269
4270         {
4271                 MonoInst *load, *and_, *cmp, *ceq;
4272                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4273                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4274                 int dest_reg = alloc_ireg (cfg);
4275
4276                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4277                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4278                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4279                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4280
4281                 ceq->type = STACK_I4;
4282
4283                 if (!is_i4) {
4284                         load = mono_decompose_opcode (cfg, load);
4285                         and_ = mono_decompose_opcode (cfg, and_);
4286                         cmp = mono_decompose_opcode (cfg, cmp);
4287                         ceq = mono_decompose_opcode (cfg, ceq);
4288                 }
4289
4290                 return ceq;
4291         }
4292 }
4293
4294 /*
4295  * Returns NULL and set the cfg exception on error.
4296  */
4297 static G_GNUC_UNUSED MonoInst*
4298 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
4299 {
4300         MonoInst *ptr;
4301         int dreg;
4302         gpointer trampoline;
4303         MonoInst *obj, *method_ins, *tramp_ins;
4304         MonoDomain *domain;
4305         guint8 **code_slot;
4306
4307         if (virtual_ && !cfg->llvm_only) {
4308                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4309                 g_assert (invoke);
4310
4311                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4312                         return NULL;
4313         }
4314
4315         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
4316         if (!obj)
4317                 return NULL;
4318
4319         /* Inline the contents of mono_delegate_ctor */
4320
4321         /* Set target field */
4322         /* Optimize away setting of NULL target */
4323         if (!MONO_INS_IS_PCONST_NULL (target)) {
4324                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4325                 if (cfg->gen_write_barriers) {
4326                         dreg = alloc_preg (cfg);
4327                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4328                         emit_write_barrier (cfg, ptr, target);
4329                 }
4330         }
4331
4332         /* Set method field */
4333         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4334         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4335
4336         /* 
4337          * To avoid looking up the compiled code belonging to the target method
4338          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4339          * store it, and we fill it after the method has been compiled.
4340          */
4341         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4342                 MonoInst *code_slot_ins;
4343
4344                 if (context_used) {
4345                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4346                 } else {
4347                         domain = mono_domain_get ();
4348                         mono_domain_lock (domain);
4349                         if (!domain_jit_info (domain)->method_code_hash)
4350                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4351                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4352                         if (!code_slot) {
4353                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
4354                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4355                         }
4356                         mono_domain_unlock (domain);
4357
4358                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4359                 }
4360                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4361         }
4362
4363         if (cfg->llvm_only) {
4364                 MonoInst *args [16];
4365
4366                 if (virtual_) {
4367                         args [0] = obj;
4368                         args [1] = target;
4369                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4370                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
4371                 } else {
4372                         args [0] = obj;
4373                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
4374                 }
4375
4376                 return obj;
4377         }
4378
4379         if (cfg->compile_aot) {
4380                 MonoDelegateClassMethodPair *del_tramp;
4381
4382                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4383                 del_tramp->klass = klass;
4384                 del_tramp->method = context_used ? NULL : method;
4385                 del_tramp->is_virtual = virtual_;
4386                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4387         } else {
4388                 if (virtual_)
4389                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4390                 else
4391                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4392                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4393         }
4394
4395         /* Set invoke_impl field */
4396         if (virtual_) {
4397                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4398         } else {
4399                 dreg = alloc_preg (cfg);
4400                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4401                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4402
4403                 dreg = alloc_preg (cfg);
4404                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4405                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4406         }
4407
4408         dreg = alloc_preg (cfg);
4409         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
4410         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
4411
4412         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4413
4414         return obj;
4415 }
4416
4417 static MonoInst*
4418 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4419 {
4420         MonoJitICallInfo *info;
4421
4422         /* Need to register the icall so it gets an icall wrapper */
4423         info = mono_get_array_new_va_icall (rank);
4424
4425         cfg->flags |= MONO_CFG_HAS_VARARGS;
4426
4427         /* mono_array_new_va () needs a vararg calling convention */
4428         cfg->exception_message = g_strdup ("array-new");
4429         cfg->disable_llvm = TRUE;
4430
4431         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4432         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4433 }
4434
4435 /*
4436  * handle_constrained_gsharedvt_call:
4437  *
4438  *   Handle constrained calls where the receiver is a gsharedvt type.
4439  * Return the instruction representing the call. Set the cfg exception on failure.
4440  */
4441 static MonoInst*
4442 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
4443                                                                    gboolean *ref_emit_widen)
4444 {
4445         MonoInst *ins = NULL;
4446         gboolean emit_widen = *ref_emit_widen;
4447
4448         /*
4449          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
4450          * 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
4451          * pack the arguments into an array, and do the rest of the work in in an icall.
4452          */
4453         if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
4454                 (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)) &&
4455                 (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]))))) {
4456                 MonoInst *args [16];
4457
4458                 /*
4459                  * This case handles calls to
4460                  * - object:ToString()/Equals()/GetHashCode(),
4461                  * - System.IComparable<T>:CompareTo()
4462                  * - System.IEquatable<T>:Equals ()
4463                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
4464                  */
4465
4466                 args [0] = sp [0];
4467                 if (mono_method_check_context_used (cmethod))
4468                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
4469                 else
4470                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
4471                 args [2] = mini_emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
4472
4473                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
4474                 if (fsig->hasthis && fsig->param_count) {
4475                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
4476                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
4477                         ins->dreg = alloc_preg (cfg);
4478                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
4479                         MONO_ADD_INS (cfg->cbb, ins);
4480                         args [4] = ins;
4481
4482                         if (mini_is_gsharedvt_type (fsig->params [0])) {
4483                                 int addr_reg, deref_arg_reg;
4484
4485                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4486                                 deref_arg_reg = alloc_preg (cfg);
4487                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
4488                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
4489
4490                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
4491                                 addr_reg = ins->dreg;
4492                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
4493                         } else {
4494                                 EMIT_NEW_ICONST (cfg, args [3], 0);
4495                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
4496                         }
4497                 } else {
4498                         EMIT_NEW_ICONST (cfg, args [3], 0);
4499                         EMIT_NEW_ICONST (cfg, args [4], 0);
4500                 }
4501                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
4502                 emit_widen = FALSE;
4503
4504                 if (mini_is_gsharedvt_type (fsig->ret)) {
4505                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
4506                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mono_class_is_enum (mono_class_from_mono_type (fsig->ret))) {
4507                         MonoInst *add;
4508
4509                         /* Unbox */
4510                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
4511                         MONO_ADD_INS (cfg->cbb, add);
4512                         /* Load value */
4513                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
4514                         MONO_ADD_INS (cfg->cbb, ins);
4515                         /* ins represents the call result */
4516                 }
4517         } else {
4518                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
4519         }
4520
4521         *ref_emit_widen = emit_widen;
4522
4523         return ins;
4524
4525  exception_exit:
4526         return NULL;
4527 }
4528
4529 static void
4530 mono_emit_load_got_addr (MonoCompile *cfg)
4531 {
4532         MonoInst *getaddr, *dummy_use;
4533
4534         if (!cfg->got_var || cfg->got_var_allocated)
4535                 return;
4536
4537         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4538         getaddr->cil_code = cfg->header->code;
4539         getaddr->dreg = cfg->got_var->dreg;
4540
4541         /* Add it to the start of the first bblock */
4542         if (cfg->bb_entry->code) {
4543                 getaddr->next = cfg->bb_entry->code;
4544                 cfg->bb_entry->code = getaddr;
4545         }
4546         else
4547                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4548
4549         cfg->got_var_allocated = TRUE;
4550
4551         /* 
4552          * Add a dummy use to keep the got_var alive, since real uses might
4553          * only be generated by the back ends.
4554          * Add it to end_bblock, so the variable's lifetime covers the whole
4555          * method.
4556          * It would be better to make the usage of the got var explicit in all
4557          * cases when the backend needs it (i.e. calls, throw etc.), so this
4558          * wouldn't be needed.
4559          */
4560         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4561         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4562 }
4563
4564 static int inline_limit;
4565 static gboolean inline_limit_inited;
4566
4567 static gboolean
4568 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4569 {
4570         MonoMethodHeaderSummary header;
4571         MonoVTable *vtable;
4572 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4573         MonoMethodSignature *sig = mono_method_signature (method);
4574         int i;
4575 #endif
4576
4577         if (cfg->disable_inline)
4578                 return FALSE;
4579         if (cfg->gsharedvt)
4580                 return FALSE;
4581
4582         if (cfg->inline_depth > 10)
4583                 return FALSE;
4584
4585         if (!mono_method_get_header_summary (method, &header))
4586                 return FALSE;
4587
4588         /*runtime, icall and pinvoke are checked by summary call*/
4589         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4590             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4591             (mono_class_is_marshalbyref (method->klass)) ||
4592             header.has_clauses)
4593                 return FALSE;
4594
4595         /* also consider num_locals? */
4596         /* Do the size check early to avoid creating vtables */
4597         if (!inline_limit_inited) {
4598                 if (g_getenv ("MONO_INLINELIMIT"))
4599                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4600                 else
4601                         inline_limit = INLINE_LENGTH_LIMIT;
4602                 inline_limit_inited = TRUE;
4603         }
4604         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4605                 return FALSE;
4606
4607         /*
4608          * if we can initialize the class of the method right away, we do,
4609          * otherwise we don't allow inlining if the class needs initialization,
4610          * since it would mean inserting a call to mono_runtime_class_init()
4611          * inside the inlined code
4612          */
4613         if (cfg->gshared && method->klass->has_cctor && mini_class_check_context_used (cfg, method->klass))
4614                 return FALSE;
4615
4616         if (!(cfg->opt & MONO_OPT_SHARED)) {
4617                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4618                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4619                         if (method->klass->has_cctor) {
4620                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4621                                 if (!vtable)
4622                                         return FALSE;
4623                                 if (!cfg->compile_aot) {
4624                                         MonoError error;
4625                                         if (!mono_runtime_class_init_full (vtable, &error)) {
4626                                                 mono_error_cleanup (&error);
4627                                                 return FALSE;
4628                                         }
4629                                 }
4630                         }
4631                 } else if (mono_class_is_before_field_init (method->klass)) {
4632                         if (cfg->run_cctors && method->klass->has_cctor) {
4633                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4634                                 if (!method->klass->runtime_info)
4635                                         /* No vtable created yet */
4636                                         return FALSE;
4637                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4638                                 if (!vtable)
4639                                         return FALSE;
4640                                 /* This makes so that inline cannot trigger */
4641                                 /* .cctors: too many apps depend on them */
4642                                 /* running with a specific order... */
4643                                 if (! vtable->initialized)
4644                                         return FALSE;
4645                                 MonoError error;
4646                                 if (!mono_runtime_class_init_full (vtable, &error)) {
4647                                         mono_error_cleanup (&error);
4648                                         return FALSE;
4649                                 }
4650                         }
4651                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4652                         if (!method->klass->runtime_info)
4653                                 /* No vtable created yet */
4654                                 return FALSE;
4655                         vtable = mono_class_vtable (cfg->domain, method->klass);
4656                         if (!vtable)
4657                                 return FALSE;
4658                         if (!vtable->initialized)
4659                                 return FALSE;
4660                 }
4661         } else {
4662                 /* 
4663                  * If we're compiling for shared code
4664                  * the cctor will need to be run at aot method load time, for example,
4665                  * or at the end of the compilation of the inlining method.
4666                  */
4667                 if (mono_class_needs_cctor_run (method->klass, NULL) && !mono_class_is_before_field_init (method->klass))
4668                         return FALSE;
4669         }
4670
4671 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4672         if (mono_arch_is_soft_float ()) {
4673                 /* FIXME: */
4674                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4675                         return FALSE;
4676                 for (i = 0; i < sig->param_count; ++i)
4677                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4678                                 return FALSE;
4679         }
4680 #endif
4681
4682         if (g_list_find (cfg->dont_inline, method))
4683                 return FALSE;
4684
4685         return TRUE;
4686 }
4687
4688 static gboolean
4689 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4690 {
4691         if (!cfg->compile_aot) {
4692                 g_assert (vtable);
4693                 if (vtable->initialized)
4694                         return FALSE;
4695         }
4696
4697         if (mono_class_is_before_field_init (klass)) {
4698                 if (cfg->method == method)
4699                         return FALSE;
4700         }
4701
4702         if (!mono_class_needs_cctor_run (klass, method))
4703                 return FALSE;
4704
4705         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4706                 /* The initialization is already done before the method is called */
4707                 return FALSE;
4708
4709         return TRUE;
4710 }
4711
4712 MonoInst*
4713 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4714 {
4715         MonoInst *ins;
4716         guint32 size;
4717         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4718         int context_used;
4719
4720         if (mini_is_gsharedvt_variable_klass (klass)) {
4721                 size = -1;
4722         } else {
4723                 mono_class_init (klass);
4724                 size = mono_class_array_element_size (klass);
4725         }
4726
4727         mult_reg = alloc_preg (cfg);
4728         array_reg = arr->dreg;
4729         index_reg = index->dreg;
4730
4731 #if SIZEOF_REGISTER == 8
4732         /* The array reg is 64 bits but the index reg is only 32 */
4733         if (COMPILE_LLVM (cfg)) {
4734                 /* Not needed */
4735                 index2_reg = index_reg;
4736         } else {
4737                 index2_reg = alloc_preg (cfg);
4738                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4739         }
4740 #else
4741         if (index->type == STACK_I8) {
4742                 index2_reg = alloc_preg (cfg);
4743                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4744         } else {
4745                 index2_reg = index_reg;
4746         }
4747 #endif
4748
4749         if (bcheck)
4750                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4751
4752 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4753         if (size == 1 || size == 2 || size == 4 || size == 8) {
4754                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4755
4756                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
4757                 ins->klass = mono_class_get_element_class (klass);
4758                 ins->type = STACK_MP;
4759
4760                 return ins;
4761         }
4762 #endif          
4763
4764         add_reg = alloc_ireg_mp (cfg);
4765
4766         if (size == -1) {
4767                 MonoInst *rgctx_ins;
4768
4769                 /* gsharedvt */
4770                 g_assert (cfg->gshared);
4771                 context_used = mini_class_check_context_used (cfg, klass);
4772                 g_assert (context_used);
4773                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4774                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4775         } else {
4776                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4777         }
4778         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4779         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4780         ins->klass = mono_class_get_element_class (klass);
4781         ins->type = STACK_MP;
4782         MONO_ADD_INS (cfg->cbb, ins);
4783
4784         return ins;
4785 }
4786
4787 static MonoInst*
4788 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4789 {
4790         int bounds_reg = alloc_preg (cfg);
4791         int add_reg = alloc_ireg_mp (cfg);
4792         int mult_reg = alloc_preg (cfg);
4793         int mult2_reg = alloc_preg (cfg);
4794         int low1_reg = alloc_preg (cfg);
4795         int low2_reg = alloc_preg (cfg);
4796         int high1_reg = alloc_preg (cfg);
4797         int high2_reg = alloc_preg (cfg);
4798         int realidx1_reg = alloc_preg (cfg);
4799         int realidx2_reg = alloc_preg (cfg);
4800         int sum_reg = alloc_preg (cfg);
4801         int index1, index2, tmpreg;
4802         MonoInst *ins;
4803         guint32 size;
4804
4805         mono_class_init (klass);
4806         size = mono_class_array_element_size (klass);
4807
4808         index1 = index_ins1->dreg;
4809         index2 = index_ins2->dreg;
4810
4811 #if SIZEOF_REGISTER == 8
4812         /* The array reg is 64 bits but the index reg is only 32 */
4813         if (COMPILE_LLVM (cfg)) {
4814                 /* Not needed */
4815         } else {
4816                 tmpreg = alloc_preg (cfg);
4817                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4818                 index1 = tmpreg;
4819                 tmpreg = alloc_preg (cfg);
4820                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4821                 index2 = tmpreg;
4822         }
4823 #else
4824         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4825         tmpreg = -1;
4826 #endif
4827
4828         /* range checking */
4829         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4830                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4831
4832         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4833                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4834         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4835         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4836                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4837         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4838         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4839
4840         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4841                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4842         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4843         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4844                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4845         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4846         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4847
4848         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4849         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4850         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4851         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4852         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4853
4854         ins->type = STACK_MP;
4855         ins->klass = klass;
4856         MONO_ADD_INS (cfg->cbb, ins);
4857
4858         return ins;
4859 }
4860
4861 static MonoInst*
4862 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4863 {
4864         int rank;
4865         MonoInst *addr;
4866         MonoMethod *addr_method;
4867         int element_size;
4868         MonoClass *eclass = cmethod->klass->element_class;
4869
4870         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4871
4872         if (rank == 1)
4873                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
4874
4875         /* emit_ldelema_2 depends on OP_LMUL */
4876         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
4877                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
4878         }
4879
4880         if (mini_is_gsharedvt_variable_klass (eclass))
4881                 element_size = 0;
4882         else
4883                 element_size = mono_class_array_element_size (eclass);
4884         addr_method = mono_marshal_get_array_address (rank, element_size);
4885         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4886
4887         return addr;
4888 }
4889
4890 static MonoBreakPolicy
4891 always_insert_breakpoint (MonoMethod *method)
4892 {
4893         return MONO_BREAK_POLICY_ALWAYS;
4894 }
4895
4896 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4897
4898 /**
4899  * mono_set_break_policy:
4900  * policy_callback: the new callback function
4901  *
4902  * Allow embedders to decide wherther to actually obey breakpoint instructions
4903  * (both break IL instructions and Debugger.Break () method calls), for example
4904  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4905  * untrusted or semi-trusted code.
4906  *
4907  * @policy_callback will be called every time a break point instruction needs to
4908  * be inserted with the method argument being the method that calls Debugger.Break()
4909  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4910  * if it wants the breakpoint to not be effective in the given method.
4911  * #MONO_BREAK_POLICY_ALWAYS is the default.
4912  */
4913 void
4914 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4915 {
4916         if (policy_callback)
4917                 break_policy_func = policy_callback;
4918         else
4919                 break_policy_func = always_insert_breakpoint;
4920 }
4921
4922 static gboolean
4923 should_insert_brekpoint (MonoMethod *method) {
4924         switch (break_policy_func (method)) {
4925         case MONO_BREAK_POLICY_ALWAYS:
4926                 return TRUE;
4927         case MONO_BREAK_POLICY_NEVER:
4928                 return FALSE;
4929         case MONO_BREAK_POLICY_ON_DBG:
4930                 g_warning ("mdb no longer supported");
4931                 return FALSE;
4932         default:
4933                 g_warning ("Incorrect value returned from break policy callback");
4934                 return FALSE;
4935         }
4936 }
4937
4938 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4939 static MonoInst*
4940 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4941 {
4942         MonoInst *addr, *store, *load;
4943         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4944
4945         /* the bounds check is already done by the callers */
4946         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4947         if (is_set) {
4948                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4949                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4950                 if (mini_type_is_reference (&eklass->byval_arg))
4951                         emit_write_barrier (cfg, addr, load);
4952         } else {
4953                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4954                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4955         }
4956         return store;
4957 }
4958
4959
4960 static gboolean
4961 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4962 {
4963         return mini_type_is_reference (&klass->byval_arg);
4964 }
4965
4966 static MonoInst*
4967 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
4968 {
4969         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
4970                 !(MONO_INS_IS_PCONST_NULL (sp [2]))) {
4971                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
4972                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
4973                 MonoInst *iargs [3];
4974
4975                 if (!helper->slot)
4976                         mono_class_setup_vtable (obj_array);
4977                 g_assert (helper->slot);
4978
4979                 if (sp [0]->type != STACK_OBJ)
4980                         return NULL;
4981                 if (sp [2]->type != STACK_OBJ)
4982                         return NULL;
4983
4984                 iargs [2] = sp [2];
4985                 iargs [1] = sp [1];
4986                 iargs [0] = sp [0];
4987
4988                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
4989         } else {
4990                 MonoInst *ins;
4991
4992                 if (mini_is_gsharedvt_variable_klass (klass)) {
4993                         MonoInst *addr;
4994
4995                         // FIXME-VT: OP_ICONST optimization
4996                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
4997                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4998                         ins->opcode = OP_STOREV_MEMBASE;
4999                 } else if (sp [1]->opcode == OP_ICONST) {
5000                         int array_reg = sp [0]->dreg;
5001                         int index_reg = sp [1]->dreg;
5002                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5003
5004                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5005                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5006
5007                         if (safety_checks)
5008                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5009                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5010                 } else {
5011                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5012                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5013                         if (generic_class_is_reference_type (cfg, klass))
5014                                 emit_write_barrier (cfg, addr, sp [2]);
5015                 }
5016                 return ins;
5017         }
5018 }
5019
5020 static MonoInst*
5021 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5022 {
5023         MonoClass *eklass;
5024         
5025         if (is_set)
5026                 eklass = mono_class_from_mono_type (fsig->params [2]);
5027         else
5028                 eklass = mono_class_from_mono_type (fsig->ret);
5029
5030         if (is_set) {
5031                 return emit_array_store (cfg, eklass, args, FALSE);
5032         } else {
5033                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5034                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5035                 return ins;
5036         }
5037 }
5038
5039 static gboolean
5040 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5041 {
5042         uint32_t align;
5043         int param_size, return_size;
5044
5045         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5046         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5047
5048         if (cfg->verbose_level > 3)
5049                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5050
5051         //Don't allow mixing reference types with value types
5052         if (param_klass->valuetype != return_klass->valuetype) {
5053                 if (cfg->verbose_level > 3)
5054                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5055                 return FALSE;
5056         }
5057
5058         if (!param_klass->valuetype) {
5059                 if (cfg->verbose_level > 3)
5060                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5061                 return TRUE;
5062         }
5063
5064         //That are blitable
5065         if (param_klass->has_references || return_klass->has_references)
5066                 return FALSE;
5067
5068         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5069         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5070                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5071                         if (cfg->verbose_level > 3)
5072                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5073                 return FALSE;
5074         }
5075
5076         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5077                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5078                 if (cfg->verbose_level > 3)
5079                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5080                 return FALSE;
5081         }
5082
5083         param_size = mono_class_value_size (param_klass, &align);
5084         return_size = mono_class_value_size (return_klass, &align);
5085
5086         //We can do it if sizes match
5087         if (param_size == return_size) {
5088                 if (cfg->verbose_level > 3)
5089                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5090                 return TRUE;
5091         }
5092
5093         //No simple way to handle struct if sizes don't match
5094         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5095                 if (cfg->verbose_level > 3)
5096                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5097                 return FALSE;
5098         }
5099
5100         /*
5101          * Same reg size category.
5102          * A quick note on why we don't require widening here.
5103          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5104          *
5105          * Since the source value comes from a function argument, the JIT will already have
5106          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5107          */
5108         if (param_size <= 4 && return_size <= 4) {
5109                 if (cfg->verbose_level > 3)
5110                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5111                 return TRUE;
5112         }
5113
5114         return FALSE;
5115 }
5116
5117 static MonoInst*
5118 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5119 {
5120         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5121         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5122
5123         if (mini_is_gsharedvt_variable_type (fsig->ret))
5124                 return NULL;
5125
5126         //Valuetypes that are semantically equivalent or numbers than can be widened to
5127         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5128                 return args [0];
5129
5130         //Arrays of valuetypes that are semantically equivalent
5131         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5132                 return args [0];
5133
5134         return NULL;
5135 }
5136
5137 static MonoInst*
5138 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5139 {
5140 #ifdef MONO_ARCH_SIMD_INTRINSICS
5141         MonoInst *ins = NULL;
5142
5143         if (cfg->opt & MONO_OPT_SIMD) {
5144                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5145                 if (ins)
5146                         return ins;
5147         }
5148 #endif
5149
5150         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5151 }
5152
5153 static MonoInst*
5154 emit_memory_barrier (MonoCompile *cfg, int kind)
5155 {
5156         MonoInst *ins = NULL;
5157         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5158         MONO_ADD_INS (cfg->cbb, ins);
5159         ins->backend.memory_barrier_kind = kind;
5160
5161         return ins;
5162 }
5163
5164 static MonoInst*
5165 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5166 {
5167         MonoInst *ins = NULL;
5168         int opcode = 0;
5169
5170         /* The LLVM backend supports these intrinsics */
5171         if (cmethod->klass == mono_defaults.math_class) {
5172                 if (strcmp (cmethod->name, "Sin") == 0) {
5173                         opcode = OP_SIN;
5174                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5175                         opcode = OP_COS;
5176                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5177                         opcode = OP_SQRT;
5178                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5179                         opcode = OP_ABS;
5180                 }
5181
5182                 if (opcode && fsig->param_count == 1) {
5183                         MONO_INST_NEW (cfg, ins, opcode);
5184                         ins->type = STACK_R8;
5185                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5186                         ins->sreg1 = args [0]->dreg;
5187                         MONO_ADD_INS (cfg->cbb, ins);
5188                 }
5189
5190                 opcode = 0;
5191                 if (cfg->opt & MONO_OPT_CMOV) {
5192                         if (strcmp (cmethod->name, "Min") == 0) {
5193                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5194                                         opcode = OP_IMIN;
5195                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5196                                         opcode = OP_IMIN_UN;
5197                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5198                                         opcode = OP_LMIN;
5199                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5200                                         opcode = OP_LMIN_UN;
5201                         } else if (strcmp (cmethod->name, "Max") == 0) {
5202                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5203                                         opcode = OP_IMAX;
5204                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5205                                         opcode = OP_IMAX_UN;
5206                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5207                                         opcode = OP_LMAX;
5208                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5209                                         opcode = OP_LMAX_UN;
5210                         }
5211                 }
5212
5213                 if (opcode && fsig->param_count == 2) {
5214                         MONO_INST_NEW (cfg, ins, opcode);
5215                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5216                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5217                         ins->sreg1 = args [0]->dreg;
5218                         ins->sreg2 = args [1]->dreg;
5219                         MONO_ADD_INS (cfg->cbb, ins);
5220                 }
5221         }
5222
5223         return ins;
5224 }
5225
5226 static MonoInst*
5227 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5228 {
5229         if (cmethod->klass == mono_defaults.array_class) {
5230                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5231                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5232                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5233                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5234                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5235                         return emit_array_unsafe_mov (cfg, fsig, args);
5236         }
5237
5238         return NULL;
5239 }
5240
5241 static MonoInst*
5242 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5243 {
5244         MonoInst *ins = NULL;
5245         MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5246
5247         if (cmethod->klass == mono_defaults.string_class) {
5248                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5249                         int dreg = alloc_ireg (cfg);
5250                         int index_reg = alloc_preg (cfg);
5251                         int add_reg = alloc_preg (cfg);
5252
5253 #if SIZEOF_REGISTER == 8
5254                         if (COMPILE_LLVM (cfg)) {
5255                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5256                         } else {
5257                                 /* The array reg is 64 bits but the index reg is only 32 */
5258                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5259                         }
5260 #else
5261                         index_reg = args [1]->dreg;
5262 #endif  
5263                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5264
5265 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5266                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5267                         add_reg = ins->dreg;
5268                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5269                                                                    add_reg, 0);
5270 #else
5271                         int mult_reg = alloc_preg (cfg);
5272                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5273                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5274                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5275                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5276 #endif
5277                         type_from_op (cfg, ins, NULL, NULL);
5278                         return ins;
5279                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5280                         int dreg = alloc_ireg (cfg);
5281                         /* Decompose later to allow more optimizations */
5282                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5283                         ins->type = STACK_I4;
5284                         ins->flags |= MONO_INST_FAULT;
5285                         cfg->cbb->has_array_access = TRUE;
5286                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5287
5288                         return ins;
5289                 } else 
5290                         return NULL;
5291         } else if (cmethod->klass == mono_defaults.object_class) {
5292                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5293                         int dreg = alloc_ireg_ref (cfg);
5294                         int vt_reg = alloc_preg (cfg);
5295                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5296                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5297                         type_from_op (cfg, ins, NULL, NULL);
5298
5299                         return ins;
5300                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5301                         int dreg = alloc_ireg (cfg);
5302                         int t1 = alloc_ireg (cfg);
5303         
5304                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5305                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5306                         ins->type = STACK_I4;
5307
5308                         return ins;
5309                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5310                         MONO_INST_NEW (cfg, ins, OP_NOP);
5311                         MONO_ADD_INS (cfg->cbb, ins);
5312                         return ins;
5313                 } else
5314                         return NULL;
5315         } else if (cmethod->klass == mono_defaults.array_class) {
5316                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5317                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5318                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5319                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5320
5321 #ifndef MONO_BIG_ARRAYS
5322                 /*
5323                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5324                  * Array methods.
5325                  */
5326                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5327                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5328                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5329                         int dreg = alloc_ireg (cfg);
5330                         int bounds_reg = alloc_ireg_mp (cfg);
5331                         MonoBasicBlock *end_bb, *szarray_bb;
5332                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5333
5334                         NEW_BBLOCK (cfg, end_bb);
5335                         NEW_BBLOCK (cfg, szarray_bb);
5336
5337                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5338                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5339                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5340                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5341                         /* Non-szarray case */
5342                         if (get_length)
5343                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5344                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5345                         else
5346                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5347                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5348                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5349                         MONO_START_BB (cfg, szarray_bb);
5350                         /* Szarray case */
5351                         if (get_length)
5352                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5353                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5354                         else
5355                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5356                         MONO_START_BB (cfg, end_bb);
5357
5358                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5359                         ins->type = STACK_I4;
5360                         
5361                         return ins;
5362                 }
5363 #endif
5364
5365                 if (cmethod->name [0] != 'g')
5366                         return NULL;
5367
5368                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5369                         int dreg = alloc_ireg (cfg);
5370                         int vtable_reg = alloc_preg (cfg);
5371                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5372                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5373                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5374                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5375                         type_from_op (cfg, ins, NULL, NULL);
5376
5377                         return ins;
5378                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5379                         int dreg = alloc_ireg (cfg);
5380
5381                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5382                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5383                         type_from_op (cfg, ins, NULL, NULL);
5384
5385                         return ins;
5386                 } else
5387                         return NULL;
5388         } else if (cmethod->klass == runtime_helpers_class) {
5389                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5390                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5391                         return ins;
5392                 } else if (strcmp (cmethod->name, "IsReferenceOrContainsReferences") == 0 && fsig->param_count == 0) {
5393                         MonoGenericContext *ctx = mono_method_get_context (cmethod);
5394                         g_assert (ctx);
5395                         g_assert (ctx->method_inst);
5396                         g_assert (ctx->method_inst->type_argc == 1);
5397                         MonoType *t = mini_get_underlying_type (ctx->method_inst->type_argv [0]);
5398                         MonoClass *klass = mono_class_from_mono_type (t);
5399
5400                         ins = NULL;
5401
5402                         mono_class_init (klass);
5403                         if (MONO_TYPE_IS_REFERENCE (t))
5404                                 EMIT_NEW_ICONST (cfg, ins, 1);
5405                         else if (MONO_TYPE_IS_PRIMITIVE (t))
5406                                 EMIT_NEW_ICONST (cfg, ins, 0);
5407                         else if (cfg->gshared && (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (t))
5408                                 EMIT_NEW_ICONST (cfg, ins, 1);
5409                         else if (!cfg->gshared || !mini_class_check_context_used (cfg, klass))
5410                                 EMIT_NEW_ICONST (cfg, ins, klass->has_references ? 1 : 0);
5411                         else {
5412                                 g_assert (cfg->gshared);
5413
5414                                 int context_used = mini_class_check_context_used (cfg, klass);
5415
5416                                 /* This returns 1 or 2 */
5417                                 MonoInst *info = mini_emit_get_rgctx_klass (cfg, context_used, klass,   MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS);
5418                                 int dreg = alloc_ireg (cfg);
5419                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_ISUB_IMM, dreg, info->dreg, 1);
5420                         }
5421
5422                         return ins;
5423                 } else
5424                         return NULL;
5425         } else if (cmethod->klass == mono_defaults.monitor_class) {
5426                 gboolean is_enter = FALSE;
5427                 gboolean is_v4 = FALSE;
5428
5429                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 2 && fsig->params [1]->byref) {
5430                         is_enter = TRUE;
5431                         is_v4 = TRUE;
5432                 }
5433                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 1)
5434                         is_enter = TRUE;
5435
5436                 if (is_enter) {
5437                         /*
5438                          * To make async stack traces work, icalls which can block should have a wrapper.
5439                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
5440                          */
5441                         MonoBasicBlock *end_bb;
5442
5443                         NEW_BBLOCK (cfg, end_bb);
5444
5445                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
5446                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
5447                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
5448                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_internal : (gpointer)mono_monitor_enter_internal, args);
5449                         MONO_START_BB (cfg, end_bb);
5450                         return ins;
5451                 }
5452         } else if (cmethod->klass == mono_defaults.thread_class) {
5453                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5454                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5455                         MONO_ADD_INS (cfg->cbb, ins);
5456                         return ins;
5457                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5458                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5459                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5460                         guint32 opcode = 0;
5461                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5462
5463                         if (fsig->params [0]->type == MONO_TYPE_I1)
5464                                 opcode = OP_LOADI1_MEMBASE;
5465                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5466                                 opcode = OP_LOADU1_MEMBASE;
5467                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5468                                 opcode = OP_LOADI2_MEMBASE;
5469                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5470                                 opcode = OP_LOADU2_MEMBASE;
5471                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5472                                 opcode = OP_LOADI4_MEMBASE;
5473                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5474                                 opcode = OP_LOADU4_MEMBASE;
5475                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5476                                 opcode = OP_LOADI8_MEMBASE;
5477                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5478                                 opcode = OP_LOADR4_MEMBASE;
5479                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5480                                 opcode = OP_LOADR8_MEMBASE;
5481                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5482                                 opcode = OP_LOAD_MEMBASE;
5483
5484                         if (opcode) {
5485                                 MONO_INST_NEW (cfg, ins, opcode);
5486                                 ins->inst_basereg = args [0]->dreg;
5487                                 ins->inst_offset = 0;
5488                                 MONO_ADD_INS (cfg->cbb, ins);
5489
5490                                 switch (fsig->params [0]->type) {
5491                                 case MONO_TYPE_I1:
5492                                 case MONO_TYPE_U1:
5493                                 case MONO_TYPE_I2:
5494                                 case MONO_TYPE_U2:
5495                                 case MONO_TYPE_I4:
5496                                 case MONO_TYPE_U4:
5497                                         ins->dreg = mono_alloc_ireg (cfg);
5498                                         ins->type = STACK_I4;
5499                                         break;
5500                                 case MONO_TYPE_I8:
5501                                 case MONO_TYPE_U8:
5502                                         ins->dreg = mono_alloc_lreg (cfg);
5503                                         ins->type = STACK_I8;
5504                                         break;
5505                                 case MONO_TYPE_I:
5506                                 case MONO_TYPE_U:
5507                                         ins->dreg = mono_alloc_ireg (cfg);
5508 #if SIZEOF_REGISTER == 8
5509                                         ins->type = STACK_I8;
5510 #else
5511                                         ins->type = STACK_I4;
5512 #endif
5513                                         break;
5514                                 case MONO_TYPE_R4:
5515                                 case MONO_TYPE_R8:
5516                                         ins->dreg = mono_alloc_freg (cfg);
5517                                         ins->type = STACK_R8;
5518                                         break;
5519                                 default:
5520                                         g_assert (mini_type_is_reference (fsig->params [0]));
5521                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5522                                         ins->type = STACK_OBJ;
5523                                         break;
5524                                 }
5525
5526                                 if (opcode == OP_LOADI8_MEMBASE)
5527                                         ins = mono_decompose_opcode (cfg, ins);
5528
5529                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5530
5531                                 return ins;
5532                         }
5533                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5534                         guint32 opcode = 0;
5535                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5536
5537                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5538                                 opcode = OP_STOREI1_MEMBASE_REG;
5539                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5540                                 opcode = OP_STOREI2_MEMBASE_REG;
5541                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5542                                 opcode = OP_STOREI4_MEMBASE_REG;
5543                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5544                                 opcode = OP_STOREI8_MEMBASE_REG;
5545                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5546                                 opcode = OP_STORER4_MEMBASE_REG;
5547                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5548                                 opcode = OP_STORER8_MEMBASE_REG;
5549                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5550                                 opcode = OP_STORE_MEMBASE_REG;
5551
5552                         if (opcode) {
5553                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5554
5555                                 MONO_INST_NEW (cfg, ins, opcode);
5556                                 ins->sreg1 = args [1]->dreg;
5557                                 ins->inst_destbasereg = args [0]->dreg;
5558                                 ins->inst_offset = 0;
5559                                 MONO_ADD_INS (cfg->cbb, ins);
5560
5561                                 if (opcode == OP_STOREI8_MEMBASE_REG)
5562                                         ins = mono_decompose_opcode (cfg, ins);
5563
5564                                 return ins;
5565                         }
5566                 }
5567         } else if (cmethod->klass->image == mono_defaults.corlib &&
5568                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5569                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5570                 ins = NULL;
5571
5572 #if SIZEOF_REGISTER == 8
5573                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5574                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
5575                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
5576                                 ins->dreg = mono_alloc_preg (cfg);
5577                                 ins->sreg1 = args [0]->dreg;
5578                                 ins->type = STACK_I8;
5579                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
5580                                 MONO_ADD_INS (cfg->cbb, ins);
5581                         } else {
5582                                 MonoInst *load_ins;
5583
5584                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5585
5586                                 /* 64 bit reads are already atomic */
5587                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
5588                                 load_ins->dreg = mono_alloc_preg (cfg);
5589                                 load_ins->inst_basereg = args [0]->dreg;
5590                                 load_ins->inst_offset = 0;
5591                                 load_ins->type = STACK_I8;
5592                                 MONO_ADD_INS (cfg->cbb, load_ins);
5593
5594                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5595
5596                                 ins = load_ins;
5597                         }
5598                 }
5599 #endif
5600
5601                 if (strcmp (cmethod->name, "Increment") == 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, "Decrement") == 0 && fsig->param_count == 1) {
5630                         MonoInst *ins_iconst;
5631                         guint32 opcode = 0;
5632
5633                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5634                                 opcode = OP_ATOMIC_ADD_I4;
5635                                 cfg->has_atomic_add_i4 = TRUE;
5636                         }
5637 #if SIZEOF_REGISTER == 8
5638                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5639                                 opcode = OP_ATOMIC_ADD_I8;
5640 #endif
5641                         if (opcode) {
5642                                 if (!mono_arch_opcode_supported (opcode))
5643                                         return NULL;
5644                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5645                                 ins_iconst->inst_c0 = -1;
5646                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5647                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5648
5649                                 MONO_INST_NEW (cfg, ins, opcode);
5650                                 ins->dreg = mono_alloc_ireg (cfg);
5651                                 ins->inst_basereg = args [0]->dreg;
5652                                 ins->inst_offset = 0;
5653                                 ins->sreg2 = ins_iconst->dreg;
5654                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5655                                 MONO_ADD_INS (cfg->cbb, ins);
5656                         }
5657                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
5658                         guint32 opcode = 0;
5659
5660                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5661                                 opcode = OP_ATOMIC_ADD_I4;
5662                                 cfg->has_atomic_add_i4 = TRUE;
5663                         }
5664 #if SIZEOF_REGISTER == 8
5665                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5666                                 opcode = OP_ATOMIC_ADD_I8;
5667 #endif
5668                         if (opcode) {
5669                                 if (!mono_arch_opcode_supported (opcode))
5670                                         return NULL;
5671                                 MONO_INST_NEW (cfg, ins, opcode);
5672                                 ins->dreg = mono_alloc_ireg (cfg);
5673                                 ins->inst_basereg = args [0]->dreg;
5674                                 ins->inst_offset = 0;
5675                                 ins->sreg2 = args [1]->dreg;
5676                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5677                                 MONO_ADD_INS (cfg->cbb, ins);
5678                         }
5679                 }
5680                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
5681                         MonoInst *f2i = NULL, *i2f;
5682                         guint32 opcode, f2i_opcode, i2f_opcode;
5683                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5684                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
5685
5686                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
5687                             fsig->params [0]->type == MONO_TYPE_R4) {
5688                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5689                                 f2i_opcode = OP_MOVE_F_TO_I4;
5690                                 i2f_opcode = OP_MOVE_I4_TO_F;
5691                                 cfg->has_atomic_exchange_i4 = TRUE;
5692                         }
5693 #if SIZEOF_REGISTER == 8
5694                         else if (is_ref ||
5695                                  fsig->params [0]->type == MONO_TYPE_I8 ||
5696                                  fsig->params [0]->type == MONO_TYPE_R8 ||
5697                                  fsig->params [0]->type == MONO_TYPE_I) {
5698                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5699                                 f2i_opcode = OP_MOVE_F_TO_I8;
5700                                 i2f_opcode = OP_MOVE_I8_TO_F;
5701                         }
5702 #else
5703                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
5704                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5705                                 cfg->has_atomic_exchange_i4 = TRUE;
5706                         }
5707 #endif
5708                         else
5709                                 return NULL;
5710
5711                         if (!mono_arch_opcode_supported (opcode))
5712                                 return NULL;
5713
5714                         if (is_float) {
5715                                 /* TODO: Decompose these opcodes instead of bailing here. */
5716                                 if (COMPILE_SOFT_FLOAT (cfg))
5717                                         return NULL;
5718
5719                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
5720                                 f2i->dreg = mono_alloc_ireg (cfg);
5721                                 f2i->sreg1 = args [1]->dreg;
5722                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5723                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5724                                 MONO_ADD_INS (cfg->cbb, f2i);
5725                         }
5726
5727                         MONO_INST_NEW (cfg, ins, opcode);
5728                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5729                         ins->inst_basereg = args [0]->dreg;
5730                         ins->inst_offset = 0;
5731                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
5732                         MONO_ADD_INS (cfg->cbb, ins);
5733
5734                         switch (fsig->params [0]->type) {
5735                         case MONO_TYPE_I4:
5736                                 ins->type = STACK_I4;
5737                                 break;
5738                         case MONO_TYPE_I8:
5739                                 ins->type = STACK_I8;
5740                                 break;
5741                         case MONO_TYPE_I:
5742 #if SIZEOF_REGISTER == 8
5743                                 ins->type = STACK_I8;
5744 #else
5745                                 ins->type = STACK_I4;
5746 #endif
5747                                 break;
5748                         case MONO_TYPE_R4:
5749                         case MONO_TYPE_R8:
5750                                 ins->type = STACK_R8;
5751                                 break;
5752                         default:
5753                                 g_assert (mini_type_is_reference (fsig->params [0]));
5754                                 ins->type = STACK_OBJ;
5755                                 break;
5756                         }
5757
5758                         if (is_float) {
5759                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5760                                 i2f->dreg = mono_alloc_freg (cfg);
5761                                 i2f->sreg1 = ins->dreg;
5762                                 i2f->type = STACK_R8;
5763                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5764                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5765                                 MONO_ADD_INS (cfg->cbb, i2f);
5766
5767                                 ins = i2f;
5768                         }
5769
5770                         if (cfg->gen_write_barriers && is_ref)
5771                                 emit_write_barrier (cfg, args [0], args [1]);
5772                 }
5773                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
5774                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
5775                         guint32 opcode, f2i_opcode, i2f_opcode;
5776                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
5777                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
5778
5779                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
5780                             fsig->params [1]->type == MONO_TYPE_R4) {
5781                                 opcode = OP_ATOMIC_CAS_I4;
5782                                 f2i_opcode = OP_MOVE_F_TO_I4;
5783                                 i2f_opcode = OP_MOVE_I4_TO_F;
5784                                 cfg->has_atomic_cas_i4 = TRUE;
5785                         }
5786 #if SIZEOF_REGISTER == 8
5787                         else if (is_ref ||
5788                                  fsig->params [1]->type == MONO_TYPE_I8 ||
5789                                  fsig->params [1]->type == MONO_TYPE_R8 ||
5790                                  fsig->params [1]->type == MONO_TYPE_I) {
5791                                 opcode = OP_ATOMIC_CAS_I8;
5792                                 f2i_opcode = OP_MOVE_F_TO_I8;
5793                                 i2f_opcode = OP_MOVE_I8_TO_F;
5794                         }
5795 #else
5796                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
5797                                 opcode = OP_ATOMIC_CAS_I4;
5798                                 cfg->has_atomic_cas_i4 = TRUE;
5799                         }
5800 #endif
5801                         else
5802                                 return NULL;
5803
5804                         if (!mono_arch_opcode_supported (opcode))
5805                                 return NULL;
5806
5807                         if (is_float) {
5808                                 /* TODO: Decompose these opcodes instead of bailing here. */
5809                                 if (COMPILE_SOFT_FLOAT (cfg))
5810                                         return NULL;
5811
5812                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
5813                                 f2i_new->dreg = mono_alloc_ireg (cfg);
5814                                 f2i_new->sreg1 = args [1]->dreg;
5815                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5816                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5817                                 MONO_ADD_INS (cfg->cbb, f2i_new);
5818
5819                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
5820                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
5821                                 f2i_cmp->sreg1 = args [2]->dreg;
5822                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5823                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5824                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
5825                         }
5826
5827                         MONO_INST_NEW (cfg, ins, opcode);
5828                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5829                         ins->sreg1 = args [0]->dreg;
5830                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
5831                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
5832                         MONO_ADD_INS (cfg->cbb, ins);
5833
5834                         switch (fsig->params [1]->type) {
5835                         case MONO_TYPE_I4:
5836                                 ins->type = STACK_I4;
5837                                 break;
5838                         case MONO_TYPE_I8:
5839                                 ins->type = STACK_I8;
5840                                 break;
5841                         case MONO_TYPE_I:
5842 #if SIZEOF_REGISTER == 8
5843                                 ins->type = STACK_I8;
5844 #else
5845                                 ins->type = STACK_I4;
5846 #endif
5847                                 break;
5848                         case MONO_TYPE_R4:
5849                                 ins->type = cfg->r4_stack_type;
5850                                 break;
5851                         case MONO_TYPE_R8:
5852                                 ins->type = STACK_R8;
5853                                 break;
5854                         default:
5855                                 g_assert (mini_type_is_reference (fsig->params [1]));
5856                                 ins->type = STACK_OBJ;
5857                                 break;
5858                         }
5859
5860                         if (is_float) {
5861                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5862                                 i2f->dreg = mono_alloc_freg (cfg);
5863                                 i2f->sreg1 = ins->dreg;
5864                                 i2f->type = STACK_R8;
5865                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5866                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5867                                 MONO_ADD_INS (cfg->cbb, i2f);
5868
5869                                 ins = i2f;
5870                         }
5871
5872                         if (cfg->gen_write_barriers && is_ref)
5873                                 emit_write_barrier (cfg, args [0], args [1]);
5874                 }
5875                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
5876                          fsig->params [1]->type == MONO_TYPE_I4) {
5877                         MonoInst *cmp, *ceq;
5878
5879                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5880                                 return NULL;
5881
5882                         /* int32 r = CAS (location, value, comparand); */
5883                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5884                         ins->dreg = alloc_ireg (cfg);
5885                         ins->sreg1 = args [0]->dreg;
5886                         ins->sreg2 = args [1]->dreg;
5887                         ins->sreg3 = args [2]->dreg;
5888                         ins->type = STACK_I4;
5889                         MONO_ADD_INS (cfg->cbb, ins);
5890
5891                         /* bool result = r == comparand; */
5892                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
5893                         cmp->sreg1 = ins->dreg;
5894                         cmp->sreg2 = args [2]->dreg;
5895                         cmp->type = STACK_I4;
5896                         MONO_ADD_INS (cfg->cbb, cmp);
5897
5898                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
5899                         ceq->dreg = alloc_ireg (cfg);
5900                         ceq->type = STACK_I4;
5901                         MONO_ADD_INS (cfg->cbb, ceq);
5902
5903                         /* *success = result; */
5904                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
5905
5906                         cfg->has_atomic_cas_i4 = TRUE;
5907                 }
5908                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
5909                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5910
5911                 if (ins)
5912                         return ins;
5913         } else if (cmethod->klass->image == mono_defaults.corlib &&
5914                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5915                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
5916                 ins = NULL;
5917
5918                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
5919                         guint32 opcode = 0;
5920                         MonoType *t = fsig->params [0];
5921                         gboolean is_ref;
5922                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
5923
5924                         g_assert (t->byref);
5925                         /* t is a byref type, so the reference check is more complicated */
5926                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5927                         if (t->type == MONO_TYPE_I1)
5928                                 opcode = OP_ATOMIC_LOAD_I1;
5929                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5930                                 opcode = OP_ATOMIC_LOAD_U1;
5931                         else if (t->type == MONO_TYPE_I2)
5932                                 opcode = OP_ATOMIC_LOAD_I2;
5933                         else if (t->type == MONO_TYPE_U2)
5934                                 opcode = OP_ATOMIC_LOAD_U2;
5935                         else if (t->type == MONO_TYPE_I4)
5936                                 opcode = OP_ATOMIC_LOAD_I4;
5937                         else if (t->type == MONO_TYPE_U4)
5938                                 opcode = OP_ATOMIC_LOAD_U4;
5939                         else if (t->type == MONO_TYPE_R4)
5940                                 opcode = OP_ATOMIC_LOAD_R4;
5941                         else if (t->type == MONO_TYPE_R8)
5942                                 opcode = OP_ATOMIC_LOAD_R8;
5943 #if SIZEOF_REGISTER == 8
5944                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
5945                                 opcode = OP_ATOMIC_LOAD_I8;
5946                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
5947                                 opcode = OP_ATOMIC_LOAD_U8;
5948 #else
5949                         else if (t->type == MONO_TYPE_I)
5950                                 opcode = OP_ATOMIC_LOAD_I4;
5951                         else if (is_ref || t->type == MONO_TYPE_U)
5952                                 opcode = OP_ATOMIC_LOAD_U4;
5953 #endif
5954
5955                         if (opcode) {
5956                                 if (!mono_arch_opcode_supported (opcode))
5957                                         return NULL;
5958
5959                                 MONO_INST_NEW (cfg, ins, opcode);
5960                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
5961                                 ins->sreg1 = args [0]->dreg;
5962                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
5963                                 MONO_ADD_INS (cfg->cbb, ins);
5964
5965                                 switch (t->type) {
5966                                 case MONO_TYPE_BOOLEAN:
5967                                 case MONO_TYPE_I1:
5968                                 case MONO_TYPE_U1:
5969                                 case MONO_TYPE_I2:
5970                                 case MONO_TYPE_U2:
5971                                 case MONO_TYPE_I4:
5972                                 case MONO_TYPE_U4:
5973                                         ins->type = STACK_I4;
5974                                         break;
5975                                 case MONO_TYPE_I8:
5976                                 case MONO_TYPE_U8:
5977                                         ins->type = STACK_I8;
5978                                         break;
5979                                 case MONO_TYPE_I:
5980                                 case MONO_TYPE_U:
5981 #if SIZEOF_REGISTER == 8
5982                                         ins->type = STACK_I8;
5983 #else
5984                                         ins->type = STACK_I4;
5985 #endif
5986                                         break;
5987                                 case MONO_TYPE_R4:
5988                                         ins->type = cfg->r4_stack_type;
5989                                         break;
5990                                 case MONO_TYPE_R8:
5991                                         ins->type = STACK_R8;
5992                                         break;
5993                                 default:
5994                                         g_assert (is_ref);
5995                                         ins->type = STACK_OBJ;
5996                                         break;
5997                                 }
5998                         }
5999                 }
6000
6001                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6002                         guint32 opcode = 0;
6003                         MonoType *t = fsig->params [0];
6004                         gboolean is_ref;
6005
6006                         g_assert (t->byref);
6007                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6008                         if (t->type == MONO_TYPE_I1)
6009                                 opcode = OP_ATOMIC_STORE_I1;
6010                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6011                                 opcode = OP_ATOMIC_STORE_U1;
6012                         else if (t->type == MONO_TYPE_I2)
6013                                 opcode = OP_ATOMIC_STORE_I2;
6014                         else if (t->type == MONO_TYPE_U2)
6015                                 opcode = OP_ATOMIC_STORE_U2;
6016                         else if (t->type == MONO_TYPE_I4)
6017                                 opcode = OP_ATOMIC_STORE_I4;
6018                         else if (t->type == MONO_TYPE_U4)
6019                                 opcode = OP_ATOMIC_STORE_U4;
6020                         else if (t->type == MONO_TYPE_R4)
6021                                 opcode = OP_ATOMIC_STORE_R4;
6022                         else if (t->type == MONO_TYPE_R8)
6023                                 opcode = OP_ATOMIC_STORE_R8;
6024 #if SIZEOF_REGISTER == 8
6025                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6026                                 opcode = OP_ATOMIC_STORE_I8;
6027                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6028                                 opcode = OP_ATOMIC_STORE_U8;
6029 #else
6030                         else if (t->type == MONO_TYPE_I)
6031                                 opcode = OP_ATOMIC_STORE_I4;
6032                         else if (is_ref || t->type == MONO_TYPE_U)
6033                                 opcode = OP_ATOMIC_STORE_U4;
6034 #endif
6035
6036                         if (opcode) {
6037                                 if (!mono_arch_opcode_supported (opcode))
6038                                         return NULL;
6039
6040                                 MONO_INST_NEW (cfg, ins, opcode);
6041                                 ins->dreg = args [0]->dreg;
6042                                 ins->sreg1 = args [1]->dreg;
6043                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6044                                 MONO_ADD_INS (cfg->cbb, ins);
6045
6046                                 if (cfg->gen_write_barriers && is_ref)
6047                                         emit_write_barrier (cfg, args [0], args [1]);
6048                         }
6049                 }
6050
6051                 if (ins)
6052                         return ins;
6053         } else if (cmethod->klass->image == mono_defaults.corlib &&
6054                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6055                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6056                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6057                         if (should_insert_brekpoint (cfg->method)) {
6058                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6059                         } else {
6060                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6061                                 MONO_ADD_INS (cfg->cbb, ins);
6062                         }
6063                         return ins;
6064                 }
6065         } else if (cmethod->klass->image == mono_defaults.corlib &&
6066                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6067                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6068                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6069 #ifdef TARGET_WIN32
6070                         EMIT_NEW_ICONST (cfg, ins, 1);
6071 #else
6072                         EMIT_NEW_ICONST (cfg, ins, 0);
6073 #endif
6074                 }
6075         } else if (cmethod->klass->image == mono_defaults.corlib &&
6076                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6077                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6078                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6079                         /* No stack walks are currently available, so implement this as an intrinsic */
6080                         MonoInst *assembly_ins;
6081
6082                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6083                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6084                         return ins;
6085                 }
6086         } else if (cmethod->klass->image == mono_defaults.corlib &&
6087                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6088                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6089                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6090                         /* No stack walks are currently available, so implement this as an intrinsic */
6091                         MonoInst *method_ins;
6092                         MonoMethod *declaring = cfg->method;
6093
6094                         /* This returns the declaring generic method */
6095                         if (declaring->is_inflated)
6096                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6097                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6098                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6099                         cfg->no_inline = TRUE;
6100                         if (cfg->method != cfg->current_method)
6101                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6102                         return ins;
6103                 }
6104         } else if (cmethod->klass == mono_defaults.math_class) {
6105                 /* 
6106                  * There is general branchless code for Min/Max, but it does not work for 
6107                  * all inputs:
6108                  * http://everything2.com/?node_id=1051618
6109                  */
6110         } else if (cmethod->klass == mono_defaults.systemtype_class && !strcmp (cmethod->name, "op_Equality")) {
6111                 EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg);
6112                 MONO_INST_NEW (cfg, ins, OP_PCEQ);
6113                 ins->dreg = alloc_preg (cfg);
6114                 ins->type = STACK_I4;
6115                 MONO_ADD_INS (cfg->cbb, ins);
6116                 return ins;
6117         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6118                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6119                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6120                                 !strcmp (cmethod->klass->name, "Selector")) ||
6121                            ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
6122                                  !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
6123                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6124                                 !strcmp (cmethod->klass->name, "Selector"))
6125                            ) {
6126                 if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
6127                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6128                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6129                     cfg->compile_aot) {
6130                         MonoInst *pi;
6131                         MonoJumpInfoToken *ji;
6132                         char *s;
6133
6134                         if (args [0]->opcode == OP_GOT_ENTRY) {
6135                                 pi = (MonoInst *)args [0]->inst_p1;
6136                                 g_assert (pi->opcode == OP_PATCH_INFO);
6137                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6138                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6139                         } else {
6140                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6141                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6142                         }
6143
6144                         NULLIFY_INS (args [0]);
6145
6146                         s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
6147                         return_val_if_nok (&cfg->error, NULL);
6148
6149                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6150                         ins->dreg = mono_alloc_ireg (cfg);
6151                         // FIXME: Leaks
6152                         ins->inst_p0 = s;
6153                         MONO_ADD_INS (cfg->cbb, ins);
6154                         return ins;
6155                 }
6156         }
6157
6158 #ifdef MONO_ARCH_SIMD_INTRINSICS
6159         if (cfg->opt & MONO_OPT_SIMD) {
6160                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6161                 if (ins)
6162                         return ins;
6163         }
6164 #endif
6165
6166         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6167         if (ins)
6168                 return ins;
6169
6170         if (COMPILE_LLVM (cfg)) {
6171                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6172                 if (ins)
6173                         return ins;
6174         }
6175
6176         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6177 }
6178
6179 /*
6180  * This entry point could be used later for arbitrary method
6181  * redirection.
6182  */
6183 inline static MonoInst*
6184 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6185                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6186 {
6187         if (method->klass == mono_defaults.string_class) {
6188                 /* managed string allocation support */
6189                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6190                         MonoInst *iargs [2];
6191                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6192                         MonoMethod *managed_alloc = NULL;
6193
6194                         g_assert (vtable); /*Should not fail since it System.String*/
6195 #ifndef MONO_CROSS_COMPILE
6196                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6197 #endif
6198                         if (!managed_alloc)
6199                                 return NULL;
6200                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6201                         iargs [1] = args [0];
6202                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6203                 }
6204         }
6205         return NULL;
6206 }
6207
6208 static void
6209 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6210 {
6211         MonoInst *store, *temp;
6212         int i;
6213
6214         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6215                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6216
6217                 /*
6218                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6219                  * would be different than the MonoInst's used to represent arguments, and
6220                  * the ldelema implementation can't deal with that.
6221                  * Solution: When ldelema is used on an inline argument, create a var for 
6222                  * it, emit ldelema on that var, and emit the saving code below in
6223                  * inline_method () if needed.
6224                  */
6225                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6226                 cfg->args [i] = temp;
6227                 /* This uses cfg->args [i] which is set by the preceeding line */
6228                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6229                 store->cil_code = sp [0]->cil_code;
6230                 sp++;
6231         }
6232 }
6233
6234 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6235 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6236
6237 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6238 static gboolean
6239 check_inline_called_method_name_limit (MonoMethod *called_method)
6240 {
6241         int strncmp_result;
6242         static const char *limit = NULL;
6243         
6244         if (limit == NULL) {
6245                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6246
6247                 if (limit_string != NULL)
6248                         limit = limit_string;
6249                 else
6250                         limit = "";
6251         }
6252
6253         if (limit [0] != '\0') {
6254                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6255
6256                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6257                 g_free (called_method_name);
6258         
6259                 //return (strncmp_result <= 0);
6260                 return (strncmp_result == 0);
6261         } else {
6262                 return TRUE;
6263         }
6264 }
6265 #endif
6266
6267 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6268 static gboolean
6269 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6270 {
6271         int strncmp_result;
6272         static const char *limit = NULL;
6273         
6274         if (limit == NULL) {
6275                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6276                 if (limit_string != NULL) {
6277                         limit = limit_string;
6278                 } else {
6279                         limit = "";
6280                 }
6281         }
6282
6283         if (limit [0] != '\0') {
6284                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6285
6286                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6287                 g_free (caller_method_name);
6288         
6289                 //return (strncmp_result <= 0);
6290                 return (strncmp_result == 0);
6291         } else {
6292                 return TRUE;
6293         }
6294 }
6295 #endif
6296
6297 static void
6298 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6299 {
6300         static double r8_0 = 0.0;
6301         static float r4_0 = 0.0;
6302         MonoInst *ins;
6303         int t;
6304
6305         rtype = mini_get_underlying_type (rtype);
6306         t = rtype->type;
6307
6308         if (rtype->byref) {
6309                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6310         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6311                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6312         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6313                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6314         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6315                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6316                 ins->type = STACK_R4;
6317                 ins->inst_p0 = (void*)&r4_0;
6318                 ins->dreg = dreg;
6319                 MONO_ADD_INS (cfg->cbb, ins);
6320         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6321                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6322                 ins->type = STACK_R8;
6323                 ins->inst_p0 = (void*)&r8_0;
6324                 ins->dreg = dreg;
6325                 MONO_ADD_INS (cfg->cbb, ins);
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_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6329         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6330                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6331         } else {
6332                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6333         }
6334 }
6335
6336 static void
6337 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6338 {
6339         int t;
6340
6341         rtype = mini_get_underlying_type (rtype);
6342         t = rtype->type;
6343
6344         if (rtype->byref) {
6345                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6346         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6347                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6348         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6349                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6350         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6351                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6352         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6353                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6354         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6355                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6356                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6357         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6358                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6359         } else {
6360                 emit_init_rvar (cfg, dreg, rtype);
6361         }
6362 }
6363
6364 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6365 static void
6366 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6367 {
6368         MonoInst *var = cfg->locals [local];
6369         if (COMPILE_SOFT_FLOAT (cfg)) {
6370                 MonoInst *store;
6371                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
6372                 emit_init_rvar (cfg, reg, type);
6373                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6374         } else {
6375                 if (init)
6376                         emit_init_rvar (cfg, var->dreg, type);
6377                 else
6378                         emit_dummy_init_rvar (cfg, var->dreg, type);
6379         }
6380 }
6381
6382 int
6383 mini_inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, guchar *ip, guint real_offset, gboolean inline_always)
6384 {
6385         return inline_method (cfg, cmethod, fsig, sp, ip, real_offset, inline_always);
6386 }
6387
6388 /*
6389  * inline_method:
6390  *
6391  * Return the cost of inlining CMETHOD, or zero if it should not be inlined.
6392  */
6393 static int
6394 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6395                guchar *ip, guint real_offset, gboolean inline_always)
6396 {
6397         MonoError error;
6398         MonoInst *ins, *rvar = NULL;
6399         MonoMethodHeader *cheader;
6400         MonoBasicBlock *ebblock, *sbblock;
6401         int i, costs;
6402         MonoMethod *prev_inlined_method;
6403         MonoInst **prev_locals, **prev_args;
6404         MonoType **prev_arg_types;
6405         guint prev_real_offset;
6406         GHashTable *prev_cbb_hash;
6407         MonoBasicBlock **prev_cil_offset_to_bb;
6408         MonoBasicBlock *prev_cbb;
6409         const unsigned char *prev_ip;
6410         unsigned char *prev_cil_start;
6411         guint32 prev_cil_offset_to_bb_len;
6412         MonoMethod *prev_current_method;
6413         MonoGenericContext *prev_generic_context;
6414         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
6415
6416         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6417
6418 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6419         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6420                 return 0;
6421 #endif
6422 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6423         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6424                 return 0;
6425 #endif
6426
6427         if (!fsig)
6428                 fsig = mono_method_signature (cmethod);
6429
6430         if (cfg->verbose_level > 2)
6431                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6432
6433         if (!cmethod->inline_info) {
6434                 cfg->stat_inlineable_methods++;
6435                 cmethod->inline_info = 1;
6436         }
6437
6438         /* allocate local variables */
6439         cheader = mono_method_get_header_checked (cmethod, &error);
6440         if (!cheader) {
6441                 if (inline_always) {
6442                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
6443                         mono_error_move (&cfg->error, &error);
6444                 } else {
6445                         mono_error_cleanup (&error);
6446                 }
6447                 return 0;
6448         }
6449
6450         /*Must verify before creating locals as it can cause the JIT to assert.*/
6451         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6452                 mono_metadata_free_mh (cheader);
6453                 return 0;
6454         }
6455
6456         /* allocate space to store the return value */
6457         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6458                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6459         }
6460
6461         prev_locals = cfg->locals;
6462         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
6463         for (i = 0; i < cheader->num_locals; ++i)
6464                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6465
6466         /* allocate start and end blocks */
6467         /* This is needed so if the inline is aborted, we can clean up */
6468         NEW_BBLOCK (cfg, sbblock);
6469         sbblock->real_offset = real_offset;
6470
6471         NEW_BBLOCK (cfg, ebblock);
6472         ebblock->block_num = cfg->num_bblocks++;
6473         ebblock->real_offset = real_offset;
6474
6475         prev_args = cfg->args;
6476         prev_arg_types = cfg->arg_types;
6477         prev_inlined_method = cfg->inlined_method;
6478         cfg->inlined_method = cmethod;
6479         cfg->ret_var_set = FALSE;
6480         cfg->inline_depth ++;
6481         prev_real_offset = cfg->real_offset;
6482         prev_cbb_hash = cfg->cbb_hash;
6483         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6484         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6485         prev_cil_start = cfg->cil_start;
6486         prev_ip = cfg->ip;
6487         prev_cbb = cfg->cbb;
6488         prev_current_method = cfg->current_method;
6489         prev_generic_context = cfg->generic_context;
6490         prev_ret_var_set = cfg->ret_var_set;
6491         prev_disable_inline = cfg->disable_inline;
6492
6493         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6494                 virtual_ = TRUE;
6495
6496         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
6497
6498         ret_var_set = cfg->ret_var_set;
6499
6500         cfg->inlined_method = prev_inlined_method;
6501         cfg->real_offset = prev_real_offset;
6502         cfg->cbb_hash = prev_cbb_hash;
6503         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6504         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6505         cfg->cil_start = prev_cil_start;
6506         cfg->ip = prev_ip;
6507         cfg->locals = prev_locals;
6508         cfg->args = prev_args;
6509         cfg->arg_types = prev_arg_types;
6510         cfg->current_method = prev_current_method;
6511         cfg->generic_context = prev_generic_context;
6512         cfg->ret_var_set = prev_ret_var_set;
6513         cfg->disable_inline = prev_disable_inline;
6514         cfg->inline_depth --;
6515
6516         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
6517                 if (cfg->verbose_level > 2)
6518                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6519
6520                 cfg->stat_inlined_methods++;
6521
6522                 /* always add some code to avoid block split failures */
6523                 MONO_INST_NEW (cfg, ins, OP_NOP);
6524                 MONO_ADD_INS (prev_cbb, ins);
6525
6526                 prev_cbb->next_bb = sbblock;
6527                 link_bblock (cfg, prev_cbb, sbblock);
6528
6529                 /* 
6530                  * Get rid of the begin and end bblocks if possible to aid local
6531                  * optimizations.
6532                  */
6533                 if (prev_cbb->out_count == 1)
6534                         mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6535
6536                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6537                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6538
6539                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6540                         MonoBasicBlock *prev = ebblock->in_bb [0];
6541
6542                         if (prev->next_bb == ebblock) {
6543                                 mono_merge_basic_blocks (cfg, prev, ebblock);
6544                                 cfg->cbb = prev;
6545                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6546                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
6547                                         cfg->cbb = prev_cbb;
6548                                 }
6549                         } else {
6550                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
6551                                 cfg->cbb = ebblock;
6552                         }
6553                 } else {
6554                         /* 
6555                          * Its possible that the rvar is set in some prev bblock, but not in others.
6556                          * (#1835).
6557                          */
6558                         if (rvar) {
6559                                 MonoBasicBlock *bb;
6560
6561                                 for (i = 0; i < ebblock->in_count; ++i) {
6562                                         bb = ebblock->in_bb [i];
6563
6564                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6565                                                 cfg->cbb = bb;
6566
6567                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6568                                         }
6569                                 }
6570                         }
6571
6572                         cfg->cbb = ebblock;
6573                 }
6574
6575                 if (rvar) {
6576                         /*
6577                          * If the inlined method contains only a throw, then the ret var is not 
6578                          * set, so set it to a dummy value.
6579                          */
6580                         if (!ret_var_set)
6581                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6582
6583                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6584                         *sp++ = ins;
6585                 }
6586                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6587                 return costs + 1;
6588         } else {
6589                 if (cfg->verbose_level > 2)
6590                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6591                 cfg->exception_type = MONO_EXCEPTION_NONE;
6592
6593                 /* This gets rid of the newly added bblocks */
6594                 cfg->cbb = prev_cbb;
6595         }
6596         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6597         return 0;
6598 }
6599
6600 /*
6601  * Some of these comments may well be out-of-date.
6602  * Design decisions: we do a single pass over the IL code (and we do bblock 
6603  * splitting/merging in the few cases when it's required: a back jump to an IL
6604  * address that was not already seen as bblock starting point).
6605  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6606  * Complex operations are decomposed in simpler ones right away. We need to let the 
6607  * arch-specific code peek and poke inside this process somehow (except when the 
6608  * optimizations can take advantage of the full semantic info of coarse opcodes).
6609  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6610  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6611  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6612  * opcode with value bigger than OP_LAST.
6613  * At this point the IR can be handed over to an interpreter, a dumb code generator
6614  * or to the optimizing code generator that will translate it to SSA form.
6615  *
6616  * Profiling directed optimizations.
6617  * We may compile by default with few or no optimizations and instrument the code
6618  * or the user may indicate what methods to optimize the most either in a config file
6619  * or through repeated runs where the compiler applies offline the optimizations to 
6620  * each method and then decides if it was worth it.
6621  */
6622
6623 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6624 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6625 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6626 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6627 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6628 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6629 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6630 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
6631
6632 /* offset from br.s -> br like opcodes */
6633 #define BIG_BRANCH_OFFSET 13
6634
6635 static gboolean
6636 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6637 {
6638         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6639
6640         return b == NULL || b == bb;
6641 }
6642
6643 static int
6644 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6645 {
6646         unsigned char *ip = start;
6647         unsigned char *target;
6648         int i;
6649         guint cli_addr;
6650         MonoBasicBlock *bblock;
6651         const MonoOpcode *opcode;
6652
6653         while (ip < end) {
6654                 cli_addr = ip - start;
6655                 i = mono_opcode_value ((const guint8 **)&ip, end);
6656                 if (i < 0)
6657                         UNVERIFIED;
6658                 opcode = &mono_opcodes [i];
6659                 switch (opcode->argument) {
6660                 case MonoInlineNone:
6661                         ip++; 
6662                         break;
6663                 case MonoInlineString:
6664                 case MonoInlineType:
6665                 case MonoInlineField:
6666                 case MonoInlineMethod:
6667                 case MonoInlineTok:
6668                 case MonoInlineSig:
6669                 case MonoShortInlineR:
6670                 case MonoInlineI:
6671                         ip += 5;
6672                         break;
6673                 case MonoInlineVar:
6674                         ip += 3;
6675                         break;
6676                 case MonoShortInlineVar:
6677                 case MonoShortInlineI:
6678                         ip += 2;
6679                         break;
6680                 case MonoShortInlineBrTarget:
6681                         target = start + cli_addr + 2 + (signed char)ip [1];
6682                         GET_BBLOCK (cfg, bblock, target);
6683                         ip += 2;
6684                         if (ip < end)
6685                                 GET_BBLOCK (cfg, bblock, ip);
6686                         break;
6687                 case MonoInlineBrTarget:
6688                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6689                         GET_BBLOCK (cfg, bblock, target);
6690                         ip += 5;
6691                         if (ip < end)
6692                                 GET_BBLOCK (cfg, bblock, ip);
6693                         break;
6694                 case MonoInlineSwitch: {
6695                         guint32 n = read32 (ip + 1);
6696                         guint32 j;
6697                         ip += 5;
6698                         cli_addr += 5 + 4 * n;
6699                         target = start + cli_addr;
6700                         GET_BBLOCK (cfg, bblock, target);
6701                         
6702                         for (j = 0; j < n; ++j) {
6703                                 target = start + cli_addr + (gint32)read32 (ip);
6704                                 GET_BBLOCK (cfg, bblock, target);
6705                                 ip += 4;
6706                         }
6707                         break;
6708                 }
6709                 case MonoInlineR:
6710                 case MonoInlineI8:
6711                         ip += 9;
6712                         break;
6713                 default:
6714                         g_assert_not_reached ();
6715                 }
6716
6717                 if (i == CEE_THROW) {
6718                         unsigned char *bb_start = ip - 1;
6719                         
6720                         /* Find the start of the bblock containing the throw */
6721                         bblock = NULL;
6722                         while ((bb_start >= start) && !bblock) {
6723                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6724                                 bb_start --;
6725                         }
6726                         if (bblock)
6727                                 bblock->out_of_line = 1;
6728                 }
6729         }
6730         return 0;
6731 unverified:
6732 exception_exit:
6733         *pos = ip;
6734         return 1;
6735 }
6736
6737 static inline MonoMethod *
6738 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
6739 {
6740         MonoMethod *method;
6741
6742         error_init (error);
6743
6744         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6745                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
6746                 if (context) {
6747                         method = mono_class_inflate_generic_method_checked (method, context, error);
6748                 }
6749         } else {
6750                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
6751         }
6752
6753         return method;
6754 }
6755
6756 static inline MonoMethod *
6757 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6758 {
6759         MonoError error;
6760         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
6761
6762         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
6763                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
6764                 method = NULL;
6765         }
6766
6767         if (!method && !cfg)
6768                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6769
6770         return method;
6771 }
6772
6773 static inline MonoClass*
6774 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6775 {
6776         MonoError error;
6777         MonoClass *klass;
6778
6779         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6780                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
6781                 if (context) {
6782                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
6783                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6784                 }
6785         } else {
6786                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
6787                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6788         }
6789         if (klass)
6790                 mono_class_init (klass);
6791         return klass;
6792 }
6793
6794 static inline MonoMethodSignature*
6795 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
6796 {
6797         MonoMethodSignature *fsig;
6798
6799         error_init (error);
6800         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6801                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6802         } else {
6803                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
6804                 return_val_if_nok (error, NULL);
6805         }
6806         if (context) {
6807                 fsig = mono_inflate_generic_signature(fsig, context, error);
6808         }
6809         return fsig;
6810 }
6811
6812 static MonoMethod*
6813 throw_exception (void)
6814 {
6815         static MonoMethod *method = NULL;
6816
6817         if (!method) {
6818                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6819                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6820         }
6821         g_assert (method);
6822         return method;
6823 }
6824
6825 static void
6826 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6827 {
6828         MonoMethod *thrower = throw_exception ();
6829         MonoInst *args [1];
6830
6831         EMIT_NEW_PCONST (cfg, args [0], ex);
6832         mono_emit_method_call (cfg, thrower, args, NULL);
6833 }
6834
6835 /*
6836  * Return the original method is a wrapper is specified. We can only access 
6837  * the custom attributes from the original method.
6838  */
6839 static MonoMethod*
6840 get_original_method (MonoMethod *method)
6841 {
6842         if (method->wrapper_type == MONO_WRAPPER_NONE)
6843                 return method;
6844
6845         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6846         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6847                 return NULL;
6848
6849         /* in other cases we need to find the original method */
6850         return mono_marshal_method_from_wrapper (method);
6851 }
6852
6853 static void
6854 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
6855 {
6856         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6857         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6858         if (ex)
6859                 emit_throw_exception (cfg, ex);
6860 }
6861
6862 static void
6863 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6864 {
6865         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6866         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6867         if (ex)
6868                 emit_throw_exception (cfg, ex);
6869 }
6870
6871 /*
6872  * Check that the IL instructions at ip are the array initialization
6873  * sequence and return the pointer to the data and the size.
6874  */
6875 static const char*
6876 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6877 {
6878         /*
6879          * newarr[System.Int32]
6880          * dup
6881          * ldtoken field valuetype ...
6882          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6883          */
6884         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6885                 MonoError error;
6886                 guint32 token = read32 (ip + 7);
6887                 guint32 field_token = read32 (ip + 2);
6888                 guint32 field_index = field_token & 0xffffff;
6889                 guint32 rva;
6890                 const char *data_ptr;
6891                 int size = 0;
6892                 MonoMethod *cmethod;
6893                 MonoClass *dummy_class;
6894                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
6895                 int dummy_align;
6896
6897                 if (!field) {
6898                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6899                         return NULL;
6900                 }
6901
6902                 *out_field_token = field_token;
6903
6904                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6905                 if (!cmethod)
6906                         return NULL;
6907                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6908                         return NULL;
6909                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6910                 case MONO_TYPE_BOOLEAN:
6911                 case MONO_TYPE_I1:
6912                 case MONO_TYPE_U1:
6913                         size = 1; break;
6914                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6915 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6916                 case MONO_TYPE_CHAR:
6917                 case MONO_TYPE_I2:
6918                 case MONO_TYPE_U2:
6919                         size = 2; break;
6920                 case MONO_TYPE_I4:
6921                 case MONO_TYPE_U4:
6922                 case MONO_TYPE_R4:
6923                         size = 4; break;
6924                 case MONO_TYPE_R8:
6925                 case MONO_TYPE_I8:
6926                 case MONO_TYPE_U8:
6927                         size = 8; break;
6928 #endif
6929                 default:
6930                         return NULL;
6931                 }
6932                 size *= len;
6933                 if (size > mono_type_size (field->type, &dummy_align))
6934                     return NULL;
6935                 *out_size = size;
6936                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6937                 if (!image_is_dynamic (method->klass->image)) {
6938                         field_index = read32 (ip + 2) & 0xffffff;
6939                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6940                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6941                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6942                         /* for aot code we do the lookup on load */
6943                         if (aot && data_ptr)
6944                                 return (const char *)GUINT_TO_POINTER (rva);
6945                 } else {
6946                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6947                         g_assert (!aot);
6948                         data_ptr = mono_field_get_data (field);
6949                 }
6950                 return data_ptr;
6951         }
6952         return NULL;
6953 }
6954
6955 static void
6956 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6957 {
6958         MonoError error;
6959         char *method_fname = mono_method_full_name (method, TRUE);
6960         char *method_code;
6961         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
6962
6963         if (!header) {
6964                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
6965                 mono_error_cleanup (&error);
6966         } else if (header->code_size == 0)
6967                 method_code = g_strdup ("method body is empty.");
6968         else
6969                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6970         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
6971         g_free (method_fname);
6972         g_free (method_code);
6973         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6974 }
6975
6976 static void
6977 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6978 {
6979         MonoInst *ins;
6980         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6981         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6982                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6983                 /* Optimize reg-reg moves away */
6984                 /* 
6985                  * Can't optimize other opcodes, since sp[0] might point to
6986                  * the last ins of a decomposed opcode.
6987                  */
6988                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6989         } else {
6990                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6991         }
6992 }
6993
6994 /*
6995  * ldloca inhibits many optimizations so try to get rid of it in common
6996  * cases.
6997  */
6998 static inline unsigned char *
6999 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7000 {
7001         int local, token;
7002         MonoClass *klass;
7003         MonoType *type;
7004
7005         if (size == 1) {
7006                 local = ip [1];
7007                 ip += 2;
7008         } else {
7009                 local = read16 (ip + 2);
7010                 ip += 4;
7011         }
7012         
7013         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7014                 /* From the INITOBJ case */
7015                 token = read32 (ip + 2);
7016                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7017                 CHECK_TYPELOAD (klass);
7018                 type = mini_get_underlying_type (&klass->byval_arg);
7019                 emit_init_local (cfg, local, type, TRUE);
7020                 return ip + 6;
7021         }
7022  exception_exit:
7023         return NULL;
7024 }
7025
7026 static MonoInst*
7027 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7028 {
7029         MonoInst *icall_args [16];
7030         MonoInst *call_target, *ins, *vtable_ins;
7031         int arg_reg, this_reg, vtable_reg;
7032         gboolean is_iface = mono_class_is_interface (cmethod->klass);
7033         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7034         gboolean variant_iface = FALSE;
7035         guint32 slot;
7036         int offset;
7037         gboolean special_array_interface = cmethod->klass->is_array_special_interface;
7038
7039         /*
7040          * In llvm-only mode, vtables contain function descriptors instead of
7041          * method addresses/trampolines.
7042          */
7043         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7044
7045         if (is_iface)
7046                 slot = mono_method_get_imt_slot (cmethod);
7047         else
7048                 slot = mono_method_get_vtable_index (cmethod);
7049
7050         this_reg = sp [0]->dreg;
7051
7052         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7053                 variant_iface = TRUE;
7054
7055         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7056                 /*
7057                  * The simplest case, a normal virtual call.
7058                  */
7059                 int slot_reg = alloc_preg (cfg);
7060                 int addr_reg = alloc_preg (cfg);
7061                 int arg_reg = alloc_preg (cfg);
7062                 MonoBasicBlock *non_null_bb;
7063
7064                 vtable_reg = alloc_preg (cfg);
7065                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7066                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7067
7068                 /* Load the vtable slot, which contains a function descriptor. */
7069                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7070
7071                 NEW_BBLOCK (cfg, non_null_bb);
7072
7073                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7074                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7075                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7076
7077                 /* Slow path */
7078                 // FIXME: Make the wrapper use the preserveall cconv
7079                 // FIXME: Use one icall per slot for small slot numbers ?
7080                 icall_args [0] = vtable_ins;
7081                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7082                 /* Make the icall return the vtable slot value to save some code space */
7083                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7084                 ins->dreg = slot_reg;
7085                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7086
7087                 /* Fastpath */
7088                 MONO_START_BB (cfg, non_null_bb);
7089                 /* Load the address + arg from the vtable slot */
7090                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7091                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7092
7093                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7094         }
7095
7096         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt && !special_array_interface) {
7097                 /*
7098                  * A simple interface call
7099                  *
7100                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7101                  * The imt slot contains a function descriptor for a runtime function + arg.
7102                  */
7103                 int slot_reg = alloc_preg (cfg);
7104                 int addr_reg = alloc_preg (cfg);
7105                 int arg_reg = alloc_preg (cfg);
7106                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7107
7108                 vtable_reg = alloc_preg (cfg);
7109                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7110                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7111
7112                 /*
7113                  * The slot is already initialized when the vtable is created so there is no need
7114                  * to check it here.
7115                  */
7116
7117                 /* Load the imt slot, which contains a function descriptor. */
7118                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7119
7120                 /* Load the address + arg of the imt thunk from the imt slot */
7121                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7122                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7123                 /*
7124                  * IMT thunks in llvm-only mode are C functions which take an info argument
7125                  * plus the imt method and return the ftndesc to call.
7126                  */
7127                 icall_args [0] = thunk_arg_ins;
7128                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7129                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7130                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7131
7132                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7133         }
7134
7135         if ((fsig->generic_param_count || variant_iface || special_array_interface) && !is_gsharedvt) {
7136                 /*
7137                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7138                  * dynamically extended as more instantiations are discovered.
7139                  * This handles generic virtual methods both on classes and interfaces.
7140                  */
7141                 int slot_reg = alloc_preg (cfg);
7142                 int addr_reg = alloc_preg (cfg);
7143                 int arg_reg = alloc_preg (cfg);
7144                 int ftndesc_reg = alloc_preg (cfg);
7145                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7146                 MonoBasicBlock *slowpath_bb, *end_bb;
7147
7148                 NEW_BBLOCK (cfg, slowpath_bb);
7149                 NEW_BBLOCK (cfg, end_bb);
7150
7151                 vtable_reg = alloc_preg (cfg);
7152                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7153                 if (is_iface)
7154                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7155                 else
7156                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7157
7158                 /* Load the slot, which contains a function descriptor. */
7159                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7160
7161                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7162                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7163                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7164                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7165
7166                 /* Fastpath */
7167                 /* Same as with iface calls */
7168                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7169                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7170                 icall_args [0] = thunk_arg_ins;
7171                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7172                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7173                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7174                 ftndesc_ins->dreg = ftndesc_reg;
7175                 /*
7176                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7177                  * they don't know about yet. Fall back to the slowpath in that case.
7178                  */
7179                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7180                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7181
7182                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7183
7184                 /* Slowpath */
7185                 MONO_START_BB (cfg, slowpath_bb);
7186                 icall_args [0] = vtable_ins;
7187                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7188                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7189                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7190                 if (is_iface)
7191                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7192                 else
7193                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7194                 ftndesc_ins->dreg = ftndesc_reg;
7195                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7196
7197                 /* Common case */
7198                 MONO_START_BB (cfg, end_bb);
7199                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7200         }
7201
7202         /*
7203          * Non-optimized cases
7204          */
7205         icall_args [0] = sp [0];
7206         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7207
7208         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7209                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7210
7211         arg_reg = alloc_preg (cfg);
7212         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7213         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7214
7215         g_assert (is_gsharedvt);
7216         if (is_iface)
7217                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7218         else
7219                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7220
7221         /*
7222          * Pass the extra argument even if the callee doesn't receive it, most
7223          * calling conventions allow this.
7224          */
7225         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7226 }
7227
7228 static gboolean
7229 is_exception_class (MonoClass *klass)
7230 {
7231         while (klass) {
7232                 if (klass == mono_defaults.exception_class)
7233                         return TRUE;
7234                 klass = klass->parent;
7235         }
7236         return FALSE;
7237 }
7238
7239 /*
7240  * is_jit_optimizer_disabled:
7241  *
7242  *   Determine whenever M's assembly has a DebuggableAttribute with the
7243  * IsJITOptimizerDisabled flag set.
7244  */
7245 static gboolean
7246 is_jit_optimizer_disabled (MonoMethod *m)
7247 {
7248         MonoError error;
7249         MonoAssembly *ass = m->klass->image->assembly;
7250         MonoCustomAttrInfo* attrs;
7251         MonoClass *klass;
7252         int i;
7253         gboolean val = FALSE;
7254
7255         g_assert (ass);
7256         if (ass->jit_optimizer_disabled_inited)
7257                 return ass->jit_optimizer_disabled;
7258
7259         klass = mono_class_try_get_debuggable_attribute_class ();
7260
7261         if (!klass) {
7262                 /* Linked away */
7263                 ass->jit_optimizer_disabled = FALSE;
7264                 mono_memory_barrier ();
7265                 ass->jit_optimizer_disabled_inited = TRUE;
7266                 return FALSE;
7267         }
7268
7269         attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
7270         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7271         if (attrs) {
7272                 for (i = 0; i < attrs->num_attrs; ++i) {
7273                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7274                         const gchar *p;
7275                         MonoMethodSignature *sig;
7276
7277                         if (!attr->ctor || attr->ctor->klass != klass)
7278                                 continue;
7279                         /* Decode the attribute. See reflection.c */
7280                         p = (const char*)attr->data;
7281                         g_assert (read16 (p) == 0x0001);
7282                         p += 2;
7283
7284                         // FIXME: Support named parameters
7285                         sig = mono_method_signature (attr->ctor);
7286                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7287                                 continue;
7288                         /* Two boolean arguments */
7289                         p ++;
7290                         val = *p;
7291                 }
7292                 mono_custom_attrs_free (attrs);
7293         }
7294
7295         ass->jit_optimizer_disabled = val;
7296         mono_memory_barrier ();
7297         ass->jit_optimizer_disabled_inited = TRUE;
7298
7299         return val;
7300 }
7301
7302 static gboolean
7303 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7304 {
7305         gboolean supported_tail_call;
7306         int i;
7307
7308         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7309
7310         for (i = 0; i < fsig->param_count; ++i) {
7311                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7312                         /* These can point to the current method's stack */
7313                         supported_tail_call = FALSE;
7314         }
7315         if (fsig->hasthis && cmethod->klass->valuetype)
7316                 /* this might point to the current method's stack */
7317                 supported_tail_call = FALSE;
7318         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7319                 supported_tail_call = FALSE;
7320         if (cfg->method->save_lmf)
7321                 supported_tail_call = FALSE;
7322         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7323                 supported_tail_call = FALSE;
7324         if (call_opcode != CEE_CALL)
7325                 supported_tail_call = FALSE;
7326
7327         /* Debugging support */
7328 #if 0
7329         if (supported_tail_call) {
7330                 if (!mono_debug_count ())
7331                         supported_tail_call = FALSE;
7332         }
7333 #endif
7334
7335         return supported_tail_call;
7336 }
7337
7338 /*
7339  * handle_ctor_call:
7340  *
7341  *   Handle calls made to ctors from NEWOBJ opcodes.
7342  */
7343 static void
7344 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7345                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7346 {
7347         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7348
7349         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7350                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7351                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7352                         mono_class_vtable (cfg->domain, cmethod->klass);
7353                         CHECK_TYPELOAD (cmethod->klass);
7354
7355                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7356                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7357                 } else {
7358                         if (context_used) {
7359                                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
7360                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7361                         } else {
7362                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7363
7364                                 CHECK_TYPELOAD (cmethod->klass);
7365                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7366                         }
7367                 }
7368         }
7369
7370         /* Avoid virtual calls to ctors if possible */
7371         if (mono_class_is_marshalbyref (cmethod->klass))
7372                 callvirt_this_arg = sp [0];
7373
7374         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7375                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7376                 CHECK_CFG_EXCEPTION;
7377         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7378                            mono_method_check_inlining (cfg, cmethod) &&
7379                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7380                 int costs;
7381
7382                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7383                         cfg->real_offset += 5;
7384
7385                         *inline_costs += costs - 5;
7386                 } else {
7387                         INLINE_FAILURE ("inline failure");
7388                         // FIXME-VT: Clean this up
7389                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7390                                 GSHAREDVT_FAILURE(*ip);
7391                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7392                 }
7393         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7394                 MonoInst *addr;
7395
7396                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7397
7398                 if (cfg->llvm_only) {
7399                         // FIXME: Avoid initializing vtable_arg
7400                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7401                 } else {
7402                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7403                 }
7404         } else if (context_used &&
7405                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7406                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7407                 MonoInst *cmethod_addr;
7408
7409                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7410
7411                 if (cfg->llvm_only) {
7412                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
7413                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7414                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7415                 } else {
7416                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7417                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7418
7419                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7420                 }
7421         } else {
7422                 INLINE_FAILURE ("ctor call");
7423                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7424                                                                                   callvirt_this_arg, NULL, vtable_arg);
7425         }
7426  exception_exit:
7427         return;
7428 }
7429
7430 static void
7431 emit_setret (MonoCompile *cfg, MonoInst *val)
7432 {
7433         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7434         MonoInst *ins;
7435
7436         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7437                 MonoInst *ret_addr;
7438
7439                 if (!cfg->vret_addr) {
7440                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7441                 } else {
7442                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7443
7444                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7445                         ins->klass = mono_class_from_mono_type (ret_type);
7446                 }
7447         } else {
7448 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7449                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7450                         MonoInst *iargs [1];
7451                         MonoInst *conv;
7452
7453                         iargs [0] = val;
7454                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7455                         mono_arch_emit_setret (cfg, cfg->method, conv);
7456                 } else {
7457                         mono_arch_emit_setret (cfg, cfg->method, val);
7458                 }
7459 #else
7460                 mono_arch_emit_setret (cfg, cfg->method, val);
7461 #endif
7462         }
7463 }
7464
7465 /*
7466  * mono_method_to_ir:
7467  *
7468  * Translate the .net IL into linear IR.
7469  *
7470  * @start_bblock: if not NULL, the starting basic block, used during inlining.
7471  * @end_bblock: if not NULL, the ending basic block, used during inlining.
7472  * @return_var: if not NULL, the place where the return value is stored, used during inlining.   
7473  * @inline_args: if not NULL, contains the arguments to the inline call
7474  * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise.
7475  * @is_virtual_call: whether this method is being called as a result of a call to callvirt
7476  *
7477  * This method is used to turn ECMA IL into Mono's internal Linear IR
7478  * reprensetation.  It is used both for entire methods, as well as
7479  * inlining existing methods.  In the former case, the @start_bblock,
7480  * @end_bblock, @return_var, @inline_args are all set to NULL, and the
7481  * inline_offset is set to zero.
7482  * 
7483  * Returns: the inline cost, or -1 if there was an error processing this method.
7484  */
7485 int
7486 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7487                    MonoInst *return_var, MonoInst **inline_args, 
7488                    guint inline_offset, gboolean is_virtual_call)
7489 {
7490         MonoError error;
7491         MonoInst *ins, **sp, **stack_start;
7492         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7493         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7494         MonoMethod *cmethod, *method_definition;
7495         MonoInst **arg_array;
7496         MonoMethodHeader *header;
7497         MonoImage *image;
7498         guint32 token, ins_flag;
7499         MonoClass *klass;
7500         MonoClass *constrained_class = NULL;
7501         unsigned char *ip, *end, *target, *err_pos;
7502         MonoMethodSignature *sig;
7503         MonoGenericContext *generic_context = NULL;
7504         MonoGenericContainer *generic_container = NULL;
7505         MonoType **param_types;
7506         int i, n, start_new_bblock, dreg;
7507         int num_calls = 0, inline_costs = 0;
7508         int breakpoint_id = 0;
7509         guint num_args;
7510         GSList *class_inits = NULL;
7511         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7512         int context_used;
7513         gboolean init_locals, seq_points, skip_dead_blocks;
7514         gboolean sym_seq_points = FALSE;
7515         MonoDebugMethodInfo *minfo;
7516         MonoBitSet *seq_point_locs = NULL;
7517         MonoBitSet *seq_point_set_locs = NULL;
7518
7519         cfg->disable_inline = is_jit_optimizer_disabled (method);
7520
7521         /* serialization and xdomain stuff may need access to private fields and methods */
7522         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7523         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7524         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7525         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7526         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7527         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7528
7529         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7530         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7531         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7532         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7533         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7534
7535         image = method->klass->image;
7536         header = mono_method_get_header_checked (method, &cfg->error);
7537         if (!header) {
7538                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7539                 goto exception_exit;
7540         } else {
7541                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7542         }
7543
7544         generic_container = mono_method_get_generic_container (method);
7545         sig = mono_method_signature (method);
7546         num_args = sig->hasthis + sig->param_count;
7547         ip = (unsigned char*)header->code;
7548         cfg->cil_start = ip;
7549         end = ip + header->code_size;
7550         cfg->stat_cil_code_size += header->code_size;
7551
7552         seq_points = cfg->gen_seq_points && cfg->method == method;
7553
7554         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7555                 /* We could hit a seq point before attaching to the JIT (#8338) */
7556                 seq_points = FALSE;
7557         }
7558
7559         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7560                 minfo = mono_debug_lookup_method (method);
7561                 if (minfo) {
7562                         MonoSymSeqPoint *sps;
7563                         int i, n_il_offsets;
7564
7565                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7566                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7567                         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);
7568                         sym_seq_points = TRUE;
7569                         for (i = 0; i < n_il_offsets; ++i) {
7570                                 if (sps [i].il_offset < header->code_size)
7571                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7572                         }
7573                         g_free (sps);
7574
7575                         MonoDebugMethodAsyncInfo* asyncMethod = mono_debug_lookup_method_async_debug_info (method);
7576                         if (asyncMethod) {
7577                                 for (i = 0; asyncMethod != NULL && i < asyncMethod->num_awaits; i++)
7578                                 {
7579                                         mono_bitset_set_fast (seq_point_locs, asyncMethod->resume_offsets[i]);
7580                                         mono_bitset_set_fast (seq_point_locs, asyncMethod->yield_offsets[i]);
7581                                 }
7582                                 mono_debug_free_method_async_debug_info (asyncMethod);
7583                         }
7584                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7585                         /* Methods without line number info like auto-generated property accessors */
7586                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7587                         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);
7588                         sym_seq_points = TRUE;
7589                 }
7590         }
7591
7592         /* 
7593          * Methods without init_locals set could cause asserts in various passes
7594          * (#497220). To work around this, we emit dummy initialization opcodes
7595          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7596          * on some platforms.
7597          */
7598         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
7599                 init_locals = header->init_locals;
7600         else
7601                 init_locals = TRUE;
7602
7603         method_definition = method;
7604         while (method_definition->is_inflated) {
7605                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7606                 method_definition = imethod->declaring;
7607         }
7608
7609         /* SkipVerification is not allowed if core-clr is enabled */
7610         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7611                 dont_verify = TRUE;
7612                 dont_verify_stloc = TRUE;
7613         }
7614
7615         if (sig->is_inflated)
7616                 generic_context = mono_method_get_context (method);
7617         else if (generic_container)
7618                 generic_context = &generic_container->context;
7619         cfg->generic_context = generic_context;
7620
7621         if (!cfg->gshared)
7622                 g_assert (!sig->has_type_parameters);
7623
7624         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7625                 g_assert (method->is_inflated);
7626                 g_assert (mono_method_get_context (method)->method_inst);
7627         }
7628         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7629                 g_assert (sig->generic_param_count);
7630
7631         if (cfg->method == method) {
7632                 cfg->real_offset = 0;
7633         } else {
7634                 cfg->real_offset = inline_offset;
7635         }
7636
7637         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7638         cfg->cil_offset_to_bb_len = header->code_size;
7639
7640         cfg->current_method = method;
7641
7642         if (cfg->verbose_level > 2)
7643                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7644
7645         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7646         if (sig->hasthis)
7647                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7648         for (n = 0; n < sig->param_count; ++n)
7649                 param_types [n + sig->hasthis] = sig->params [n];
7650         cfg->arg_types = param_types;
7651
7652         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7653         if (cfg->method == method) {
7654
7655                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7656                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7657
7658                 /* ENTRY BLOCK */
7659                 NEW_BBLOCK (cfg, start_bblock);
7660                 cfg->bb_entry = start_bblock;
7661                 start_bblock->cil_code = NULL;
7662                 start_bblock->cil_length = 0;
7663
7664                 /* EXIT BLOCK */
7665                 NEW_BBLOCK (cfg, end_bblock);
7666                 cfg->bb_exit = end_bblock;
7667                 end_bblock->cil_code = NULL;
7668                 end_bblock->cil_length = 0;
7669                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7670                 g_assert (cfg->num_bblocks == 2);
7671
7672                 arg_array = cfg->args;
7673
7674                 if (header->num_clauses) {
7675                         cfg->spvars = g_hash_table_new (NULL, NULL);
7676                         cfg->exvars = g_hash_table_new (NULL, NULL);
7677                 }
7678                 /* handle exception clauses */
7679                 for (i = 0; i < header->num_clauses; ++i) {
7680                         MonoBasicBlock *try_bb;
7681                         MonoExceptionClause *clause = &header->clauses [i];
7682                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7683
7684                         try_bb->real_offset = clause->try_offset;
7685                         try_bb->try_start = TRUE;
7686                         try_bb->region = ((i + 1) << 8) | clause->flags;
7687                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7688                         tblock->real_offset = clause->handler_offset;
7689                         tblock->flags |= BB_EXCEPTION_HANDLER;
7690
7691                         /*
7692                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7693                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7694                          */
7695                         if (COMPILE_LLVM (cfg))
7696                                 link_bblock (cfg, try_bb, tblock);
7697
7698                         if (*(ip + clause->handler_offset) == CEE_POP)
7699                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7700
7701                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7702                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7703                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7704                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7705                                 MONO_ADD_INS (tblock, ins);
7706
7707                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
7708                                         /* finally clauses already have a seq point */
7709                                         /* seq points for filter clauses are emitted below */
7710                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7711                                         MONO_ADD_INS (tblock, ins);
7712                                 }
7713
7714                                 /* todo: is a fault block unsafe to optimize? */
7715                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7716                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7717                         }
7718
7719                         /*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);
7720                           while (p < end) {
7721                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7722                           }*/
7723                         /* catch and filter blocks get the exception object on the stack */
7724                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7725                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7726
7727                                 /* mostly like handle_stack_args (), but just sets the input args */
7728                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7729                                 tblock->in_scount = 1;
7730                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7731                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7732
7733                                 cfg->cbb = tblock;
7734
7735 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7736                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7737                                 if (!cfg->compile_llvm) {
7738                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7739                                         ins->dreg = tblock->in_stack [0]->dreg;
7740                                         MONO_ADD_INS (tblock, ins);
7741                                 }
7742 #else
7743                                 MonoInst *dummy_use;
7744
7745                                 /* 
7746                                  * Add a dummy use for the exvar so its liveness info will be
7747                                  * correct.
7748                                  */
7749                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7750 #endif
7751
7752                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7753                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7754                                         MONO_ADD_INS (tblock, ins);
7755                                 }
7756                                 
7757                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7758                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7759                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7760                                         tblock->real_offset = clause->data.filter_offset;
7761                                         tblock->in_scount = 1;
7762                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7763                                         /* The filter block shares the exvar with the handler block */
7764                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7765                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7766                                         MONO_ADD_INS (tblock, ins);
7767                                 }
7768                         }
7769
7770                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7771                                         clause->data.catch_class &&
7772                                         cfg->gshared &&
7773                                         mono_class_check_context_used (clause->data.catch_class)) {
7774                                 /*
7775                                  * In shared generic code with catch
7776                                  * clauses containing type variables
7777                                  * the exception handling code has to
7778                                  * be able to get to the rgctx.
7779                                  * Therefore we have to make sure that
7780                                  * the vtable/mrgctx argument (for
7781                                  * static or generic methods) or the
7782                                  * "this" argument (for non-static
7783                                  * methods) are live.
7784                                  */
7785                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7786                                                 mini_method_get_context (method)->method_inst ||
7787                                                 method->klass->valuetype) {
7788                                         mono_get_vtable_var (cfg);
7789                                 } else {
7790                                         MonoInst *dummy_use;
7791
7792                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7793                                 }
7794                         }
7795                 }
7796         } else {
7797                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7798                 cfg->cbb = start_bblock;
7799                 cfg->args = arg_array;
7800                 mono_save_args (cfg, sig, inline_args);
7801         }
7802
7803         /* FIRST CODE BLOCK */
7804         NEW_BBLOCK (cfg, tblock);
7805         tblock->cil_code = ip;
7806         cfg->cbb = tblock;
7807         cfg->ip = ip;
7808
7809         ADD_BBLOCK (cfg, tblock);
7810
7811         if (cfg->method == method) {
7812                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7813                 if (breakpoint_id) {
7814                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7815                         MONO_ADD_INS (cfg->cbb, ins);
7816                 }
7817         }
7818
7819         /* we use a separate basic block for the initialization code */
7820         NEW_BBLOCK (cfg, init_localsbb);
7821         if (cfg->method == method)
7822                 cfg->bb_init = init_localsbb;
7823         init_localsbb->real_offset = cfg->real_offset;
7824         start_bblock->next_bb = init_localsbb;
7825         init_localsbb->next_bb = cfg->cbb;
7826         link_bblock (cfg, start_bblock, init_localsbb);
7827         link_bblock (cfg, init_localsbb, cfg->cbb);
7828                 
7829         cfg->cbb = init_localsbb;
7830
7831         if (cfg->gsharedvt && cfg->method == method) {
7832                 MonoGSharedVtMethodInfo *info;
7833                 MonoInst *var, *locals_var;
7834                 int dreg;
7835
7836                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7837                 info->method = cfg->method;
7838                 info->count_entries = 16;
7839                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7840                 cfg->gsharedvt_info = info;
7841
7842                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7843                 /* prevent it from being register allocated */
7844                 //var->flags |= MONO_INST_VOLATILE;
7845                 cfg->gsharedvt_info_var = var;
7846
7847                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7848                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7849
7850                 /* Allocate locals */
7851                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7852                 /* prevent it from being register allocated */
7853                 //locals_var->flags |= MONO_INST_VOLATILE;
7854                 cfg->gsharedvt_locals_var = locals_var;
7855
7856                 dreg = alloc_ireg (cfg);
7857                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7858
7859                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7860                 ins->dreg = locals_var->dreg;
7861                 ins->sreg1 = dreg;
7862                 MONO_ADD_INS (cfg->cbb, ins);
7863                 cfg->gsharedvt_locals_var_ins = ins;
7864                 
7865                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7866                 /*
7867                 if (init_locals)
7868                         ins->flags |= MONO_INST_INIT;
7869                 */
7870         }
7871
7872         if (mono_security_core_clr_enabled ()) {
7873                 /* check if this is native code, e.g. an icall or a p/invoke */
7874                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7875                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7876                         if (wrapped) {
7877                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7878                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7879
7880                                 /* if this ia a native call then it can only be JITted from platform code */
7881                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7882                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7883                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7884                                                         mono_get_exception_method_access ();
7885                                                 emit_throw_exception (cfg, ex);
7886                                         }
7887                                 }
7888                         }
7889                 }
7890         }
7891
7892         CHECK_CFG_EXCEPTION;
7893
7894         if (header->code_size == 0)
7895                 UNVERIFIED;
7896
7897         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7898                 ip = err_pos;
7899                 UNVERIFIED;
7900         }
7901
7902         if (cfg->method == method)
7903                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
7904
7905         for (n = 0; n < header->num_locals; ++n) {
7906                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7907                         UNVERIFIED;
7908         }
7909         class_inits = NULL;
7910
7911         /* We force the vtable variable here for all shared methods
7912            for the possibility that they might show up in a stack
7913            trace where their exact instantiation is needed. */
7914         if (cfg->gshared && method == cfg->method) {
7915                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7916                                 mini_method_get_context (method)->method_inst ||
7917                                 method->klass->valuetype) {
7918                         mono_get_vtable_var (cfg);
7919                 } else {
7920                         /* FIXME: Is there a better way to do this?
7921                            We need the variable live for the duration
7922                            of the whole method. */
7923                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7924                 }
7925         }
7926
7927         /* add a check for this != NULL to inlined methods */
7928         if (is_virtual_call) {
7929                 MonoInst *arg_ins;
7930
7931                 NEW_ARGLOAD (cfg, arg_ins, 0);
7932                 MONO_ADD_INS (cfg->cbb, arg_ins);
7933                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7934         }
7935
7936         skip_dead_blocks = !dont_verify;
7937         if (skip_dead_blocks) {
7938                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
7939                 CHECK_CFG_ERROR;
7940                 g_assert (bb);
7941         }
7942
7943         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7944         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7945
7946         ins_flag = 0;
7947         start_new_bblock = 0;
7948         while (ip < end) {
7949                 if (cfg->method == method)
7950                         cfg->real_offset = ip - header->code;
7951                 else
7952                         cfg->real_offset = inline_offset;
7953                 cfg->ip = ip;
7954
7955                 context_used = 0;
7956
7957                 if (start_new_bblock) {
7958                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
7959                         if (start_new_bblock == 2) {
7960                                 g_assert (ip == tblock->cil_code);
7961                         } else {
7962                                 GET_BBLOCK (cfg, tblock, ip);
7963                         }
7964                         cfg->cbb->next_bb = tblock;
7965                         cfg->cbb = tblock;
7966                         start_new_bblock = 0;
7967                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
7968                                 if (cfg->verbose_level > 3)
7969                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7970                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7971                                 *sp++ = ins;
7972                         }
7973                         if (class_inits)
7974                                 g_slist_free (class_inits);
7975                         class_inits = NULL;
7976                 } else {
7977                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
7978                                 link_bblock (cfg, cfg->cbb, tblock);
7979                                 if (sp != stack_start) {
7980                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7981                                         sp = stack_start;
7982                                         CHECK_UNVERIFIABLE (cfg);
7983                                 }
7984                                 cfg->cbb->next_bb = tblock;
7985                                 cfg->cbb = tblock;
7986                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
7987                                         if (cfg->verbose_level > 3)
7988                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7989                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7990                                         *sp++ = ins;
7991                                 }
7992                                 g_slist_free (class_inits);
7993                                 class_inits = NULL;
7994                         }
7995                 }
7996
7997                 if (skip_dead_blocks) {
7998                         int ip_offset = ip - header->code;
7999
8000                         if (ip_offset == bb->end)
8001                                 bb = bb->next;
8002
8003                         if (bb->dead) {
8004                                 int op_size = mono_opcode_size (ip, end);
8005                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8006
8007                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8008
8009                                 if (ip_offset + op_size == bb->end) {
8010                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8011                                         MONO_ADD_INS (cfg->cbb, ins);
8012                                         start_new_bblock = 1;
8013                                 }
8014
8015                                 ip += op_size;
8016                                 continue;
8017                         }
8018                 }
8019                 /*
8020                  * Sequence points are points where the debugger can place a breakpoint.
8021                  * Currently, we generate these automatically at points where the IL
8022                  * stack is empty.
8023                  */
8024                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8025                         /*
8026                          * Make methods interruptable at the beginning, and at the targets of
8027                          * backward branches.
8028                          * Also, do this at the start of every bblock in methods with clauses too,
8029                          * to be able to handle instructions with inprecise control flow like
8030                          * throw/endfinally.
8031                          * Backward branches are handled at the end of method-to-ir ().
8032                          */
8033                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8034                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8035
8036                         /* Avoid sequence points on empty IL like .volatile */
8037                         // FIXME: Enable this
8038                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8039                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8040                         if ((sp != stack_start) && !sym_seq_point)
8041                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8042                         MONO_ADD_INS (cfg->cbb, ins);
8043
8044                         if (sym_seq_points)
8045                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8046                 }
8047
8048                 cfg->cbb->real_offset = cfg->real_offset;
8049
8050                 if ((cfg->method == method) && cfg->coverage_info) {
8051                         guint32 cil_offset = ip - header->code;
8052                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8053
8054                         /* TODO: Use an increment here */
8055 #if defined(TARGET_X86)
8056                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8057                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8058                         ins->inst_imm = 1;
8059                         MONO_ADD_INS (cfg->cbb, ins);
8060 #else
8061                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8062                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8063 #endif
8064                 }
8065
8066                 if (cfg->verbose_level > 3)
8067                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8068
8069                 switch (*ip) {
8070                 case CEE_NOP:
8071                         if (seq_points && !sym_seq_points && sp != stack_start) {
8072                                 /*
8073                                  * The C# compiler uses these nops to notify the JIT that it should
8074                                  * insert seq points.
8075                                  */
8076                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8077                                 MONO_ADD_INS (cfg->cbb, ins);
8078                         }
8079                         if (cfg->keep_cil_nops)
8080                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8081                         else
8082                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8083                         ip++;
8084                         MONO_ADD_INS (cfg->cbb, ins);
8085                         break;
8086                 case CEE_BREAK:
8087                         if (should_insert_brekpoint (cfg->method)) {
8088                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8089                         } else {
8090                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8091                         }
8092                         ip++;
8093                         MONO_ADD_INS (cfg->cbb, ins);
8094                         break;
8095                 case CEE_LDARG_0:
8096                 case CEE_LDARG_1:
8097                 case CEE_LDARG_2:
8098                 case CEE_LDARG_3:
8099                         CHECK_STACK_OVF (1);
8100                         n = (*ip)-CEE_LDARG_0;
8101                         CHECK_ARG (n);
8102                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8103                         ip++;
8104                         *sp++ = ins;
8105                         break;
8106                 case CEE_LDLOC_0:
8107                 case CEE_LDLOC_1:
8108                 case CEE_LDLOC_2:
8109                 case CEE_LDLOC_3:
8110                         CHECK_STACK_OVF (1);
8111                         n = (*ip)-CEE_LDLOC_0;
8112                         CHECK_LOCAL (n);
8113                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8114                         ip++;
8115                         *sp++ = ins;
8116                         break;
8117                 case CEE_STLOC_0:
8118                 case CEE_STLOC_1:
8119                 case CEE_STLOC_2:
8120                 case CEE_STLOC_3: {
8121                         CHECK_STACK (1);
8122                         n = (*ip)-CEE_STLOC_0;
8123                         CHECK_LOCAL (n);
8124                         --sp;
8125                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8126                                 UNVERIFIED;
8127                         emit_stloc_ir (cfg, sp, header, n);
8128                         ++ip;
8129                         inline_costs += 1;
8130                         break;
8131                         }
8132                 case CEE_LDARG_S:
8133                         CHECK_OPSIZE (2);
8134                         CHECK_STACK_OVF (1);
8135                         n = ip [1];
8136                         CHECK_ARG (n);
8137                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8138                         *sp++ = ins;
8139                         ip += 2;
8140                         break;
8141                 case CEE_LDARGA_S:
8142                         CHECK_OPSIZE (2);
8143                         CHECK_STACK_OVF (1);
8144                         n = ip [1];
8145                         CHECK_ARG (n);
8146                         NEW_ARGLOADA (cfg, ins, n);
8147                         MONO_ADD_INS (cfg->cbb, ins);
8148                         *sp++ = ins;
8149                         ip += 2;
8150                         break;
8151                 case CEE_STARG_S:
8152                         CHECK_OPSIZE (2);
8153                         CHECK_STACK (1);
8154                         --sp;
8155                         n = ip [1];
8156                         CHECK_ARG (n);
8157                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8158                                 UNVERIFIED;
8159                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8160                         ip += 2;
8161                         break;
8162                 case CEE_LDLOC_S:
8163                         CHECK_OPSIZE (2);
8164                         CHECK_STACK_OVF (1);
8165                         n = ip [1];
8166                         CHECK_LOCAL (n);
8167                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8168                         *sp++ = ins;
8169                         ip += 2;
8170                         break;
8171                 case CEE_LDLOCA_S: {
8172                         unsigned char *tmp_ip;
8173                         CHECK_OPSIZE (2);
8174                         CHECK_STACK_OVF (1);
8175                         CHECK_LOCAL (ip [1]);
8176
8177                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8178                                 ip = tmp_ip;
8179                                 inline_costs += 1;
8180                                 break;
8181                         }
8182
8183                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8184                         *sp++ = ins;
8185                         ip += 2;
8186                         break;
8187                 }
8188                 case CEE_STLOC_S:
8189                         CHECK_OPSIZE (2);
8190                         CHECK_STACK (1);
8191                         --sp;
8192                         CHECK_LOCAL (ip [1]);
8193                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8194                                 UNVERIFIED;
8195                         emit_stloc_ir (cfg, sp, header, ip [1]);
8196                         ip += 2;
8197                         inline_costs += 1;
8198                         break;
8199                 case CEE_LDNULL:
8200                         CHECK_STACK_OVF (1);
8201                         EMIT_NEW_PCONST (cfg, ins, NULL);
8202                         ins->type = STACK_OBJ;
8203                         ++ip;
8204                         *sp++ = ins;
8205                         break;
8206                 case CEE_LDC_I4_M1:
8207                         CHECK_STACK_OVF (1);
8208                         EMIT_NEW_ICONST (cfg, ins, -1);
8209                         ++ip;
8210                         *sp++ = ins;
8211                         break;
8212                 case CEE_LDC_I4_0:
8213                 case CEE_LDC_I4_1:
8214                 case CEE_LDC_I4_2:
8215                 case CEE_LDC_I4_3:
8216                 case CEE_LDC_I4_4:
8217                 case CEE_LDC_I4_5:
8218                 case CEE_LDC_I4_6:
8219                 case CEE_LDC_I4_7:
8220                 case CEE_LDC_I4_8:
8221                         CHECK_STACK_OVF (1);
8222                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8223                         ++ip;
8224                         *sp++ = ins;
8225                         break;
8226                 case CEE_LDC_I4_S:
8227                         CHECK_OPSIZE (2);
8228                         CHECK_STACK_OVF (1);
8229                         ++ip;
8230                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8231                         ++ip;
8232                         *sp++ = ins;
8233                         break;
8234                 case CEE_LDC_I4:
8235                         CHECK_OPSIZE (5);
8236                         CHECK_STACK_OVF (1);
8237                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8238                         ip += 5;
8239                         *sp++ = ins;
8240                         break;
8241                 case CEE_LDC_I8:
8242                         CHECK_OPSIZE (9);
8243                         CHECK_STACK_OVF (1);
8244                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8245                         ins->type = STACK_I8;
8246                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8247                         ++ip;
8248                         ins->inst_l = (gint64)read64 (ip);
8249                         MONO_ADD_INS (cfg->cbb, ins);
8250                         ip += 8;
8251                         *sp++ = ins;
8252                         break;
8253                 case CEE_LDC_R4: {
8254                         float *f;
8255                         gboolean use_aotconst = FALSE;
8256
8257 #ifdef TARGET_POWERPC
8258                         /* FIXME: Clean this up */
8259                         if (cfg->compile_aot)
8260                                 use_aotconst = TRUE;
8261 #endif
8262
8263                         /* FIXME: we should really allocate this only late in the compilation process */
8264                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8265                         CHECK_OPSIZE (5);
8266                         CHECK_STACK_OVF (1);
8267
8268                         if (use_aotconst) {
8269                                 MonoInst *cons;
8270                                 int dreg;
8271
8272                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8273
8274                                 dreg = alloc_freg (cfg);
8275                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8276                                 ins->type = cfg->r4_stack_type;
8277                         } else {
8278                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8279                                 ins->type = cfg->r4_stack_type;
8280                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8281                                 ins->inst_p0 = f;
8282                                 MONO_ADD_INS (cfg->cbb, ins);
8283                         }
8284                         ++ip;
8285                         readr4 (ip, f);
8286                         ip += 4;
8287                         *sp++ = ins;                    
8288                         break;
8289                 }
8290                 case CEE_LDC_R8: {
8291                         double *d;
8292                         gboolean use_aotconst = FALSE;
8293
8294 #ifdef TARGET_POWERPC
8295                         /* FIXME: Clean this up */
8296                         if (cfg->compile_aot)
8297                                 use_aotconst = TRUE;
8298 #endif
8299
8300                         /* FIXME: we should really allocate this only late in the compilation process */
8301                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8302                         CHECK_OPSIZE (9);
8303                         CHECK_STACK_OVF (1);
8304
8305                         if (use_aotconst) {
8306                                 MonoInst *cons;
8307                                 int dreg;
8308
8309                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8310
8311                                 dreg = alloc_freg (cfg);
8312                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8313                                 ins->type = STACK_R8;
8314                         } else {
8315                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8316                                 ins->type = STACK_R8;
8317                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8318                                 ins->inst_p0 = d;
8319                                 MONO_ADD_INS (cfg->cbb, ins);
8320                         }
8321                         ++ip;
8322                         readr8 (ip, d);
8323                         ip += 8;
8324                         *sp++ = ins;
8325                         break;
8326                 }
8327                 case CEE_DUP: {
8328                         MonoInst *temp, *store;
8329                         CHECK_STACK (1);
8330                         CHECK_STACK_OVF (1);
8331                         sp--;
8332                         ins = *sp;
8333
8334                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8335                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8336
8337                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8338                         *sp++ = ins;
8339
8340                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8341                         *sp++ = ins;
8342
8343                         ++ip;
8344                         inline_costs += 2;
8345                         break;
8346                 }
8347                 case CEE_POP:
8348                         CHECK_STACK (1);
8349                         ip++;
8350                         --sp;
8351
8352 #ifdef TARGET_X86
8353                         if (sp [0]->type == STACK_R8)
8354                                 /* we need to pop the value from the x86 FP stack */
8355                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8356 #endif
8357                         break;
8358                 case CEE_JMP: {
8359                         MonoCallInst *call;
8360                         MonoMethodSignature *fsig;
8361                         int i, n;
8362
8363                         INLINE_FAILURE ("jmp");
8364                         GSHAREDVT_FAILURE (*ip);
8365
8366                         CHECK_OPSIZE (5);
8367                         if (stack_start != sp)
8368                                 UNVERIFIED;
8369                         token = read32 (ip + 1);
8370                         /* FIXME: check the signature matches */
8371                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8372                         CHECK_CFG_ERROR;
8373  
8374                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8375                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8376
8377                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8378
8379                         fsig = mono_method_signature (cmethod);
8380                         n = fsig->param_count + fsig->hasthis;
8381                         if (cfg->llvm_only) {
8382                                 MonoInst **args;
8383
8384                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8385                                 for (i = 0; i < n; ++i)
8386                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8387                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8388                                 /*
8389                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8390                                  * have to emit a normal return since llvm expects it.
8391                                  */
8392                                 if (cfg->ret)
8393                                         emit_setret (cfg, ins);
8394                                 MONO_INST_NEW (cfg, ins, OP_BR);
8395                                 ins->inst_target_bb = end_bblock;
8396                                 MONO_ADD_INS (cfg->cbb, ins);
8397                                 link_bblock (cfg, cfg->cbb, end_bblock);
8398                                 ip += 5;
8399                                 break;
8400                         } else if (cfg->backend->have_op_tail_call) {
8401                                 /* Handle tail calls similarly to calls */
8402                                 DISABLE_AOT (cfg);
8403
8404                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8405                                 call->method = cmethod;
8406                                 call->tail_call = TRUE;
8407                                 call->signature = mono_method_signature (cmethod);
8408                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8409                                 call->inst.inst_p0 = cmethod;
8410                                 for (i = 0; i < n; ++i)
8411                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8412
8413                                 if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
8414                                         call->vret_var = cfg->vret_addr;
8415
8416                                 mono_arch_emit_call (cfg, call);
8417                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8418                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8419                         } else {
8420                                 for (i = 0; i < num_args; ++i)
8421                                         /* Prevent arguments from being optimized away */
8422                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8423
8424                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8425                                 ins = (MonoInst*)call;
8426                                 ins->inst_p0 = cmethod;
8427                                 MONO_ADD_INS (cfg->cbb, ins);
8428                         }
8429
8430                         ip += 5;
8431                         start_new_bblock = 1;
8432                         break;
8433                 }
8434                 case CEE_CALLI: {
8435                         MonoInst *addr;
8436                         MonoMethodSignature *fsig;
8437
8438                         CHECK_OPSIZE (5);
8439                         token = read32 (ip + 1);
8440
8441                         ins = NULL;
8442
8443                         //GSHAREDVT_FAILURE (*ip);
8444                         cmethod = NULL;
8445                         CHECK_STACK (1);
8446                         --sp;
8447                         addr = *sp;
8448                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
8449                         CHECK_CFG_ERROR;
8450
8451                         if (method->dynamic && fsig->pinvoke) {
8452                                 MonoInst *args [3];
8453
8454                                 /*
8455                                  * This is a call through a function pointer using a pinvoke
8456                                  * signature. Have to create a wrapper and call that instead.
8457                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8458                                  * instead based on the signature.
8459                                  */
8460                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8461                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8462                                 args [2] = addr;
8463                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8464                         }
8465
8466                         n = fsig->param_count + fsig->hasthis;
8467
8468                         CHECK_STACK (n);
8469
8470                         //g_assert (!virtual_ || fsig->hasthis);
8471
8472                         sp -= n;
8473
8474                         inline_costs += 10 * num_calls++;
8475
8476                         /*
8477                          * Making generic calls out of gsharedvt methods.
8478                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8479                          * patching gshared method addresses into a gsharedvt method.
8480                          */
8481                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8482                                 /*
8483                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8484                                  */
8485                                 MonoInst *callee = addr;
8486
8487                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8488                                         /* Not tested */
8489                                         GSHAREDVT_FAILURE (*ip);
8490
8491                                 if (cfg->llvm_only)
8492                                         // FIXME:
8493                                         GSHAREDVT_FAILURE (*ip);
8494
8495                                 addr = emit_get_rgctx_sig (cfg, context_used,
8496                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8497                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8498                                 goto calli_end;
8499                         }
8500
8501                         /* Prevent inlining of methods with indirect calls */
8502                         INLINE_FAILURE ("indirect call");
8503
8504                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8505                                 MonoJumpInfoType info_type;
8506                                 gpointer info_data;
8507
8508                                 /*
8509                                  * Instead of emitting an indirect call, emit a direct call
8510                                  * with the contents of the aotconst as the patch info.
8511                                  */
8512                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8513                                         info_type = (MonoJumpInfoType)addr->inst_c1;
8514                                         info_data = addr->inst_p0;
8515                                 } else {
8516                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
8517                                         info_data = addr->inst_right->inst_left;
8518                                 }
8519
8520                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
8521                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
8522                                         NULLIFY_INS (addr);
8523                                         goto calli_end;
8524                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8525                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8526                                         NULLIFY_INS (addr);
8527                                         goto calli_end;
8528                                 }
8529                         }
8530                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8531
8532                         calli_end:
8533
8534                         /* End of call, INS should contain the result of the call, if any */
8535
8536                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8537                                 g_assert (ins);
8538                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8539                         }
8540
8541                         CHECK_CFG_EXCEPTION;
8542
8543                         ip += 5;
8544                         ins_flag = 0;
8545                         constrained_class = NULL;
8546                         break;
8547                 }
8548                 case CEE_CALL:
8549                 case CEE_CALLVIRT: {
8550                         MonoInst *addr = NULL;
8551                         MonoMethodSignature *fsig = NULL;
8552                         int array_rank = 0;
8553                         int virtual_ = *ip == CEE_CALLVIRT;
8554                         gboolean pass_imt_from_rgctx = FALSE;
8555                         MonoInst *imt_arg = NULL;
8556                         MonoInst *keep_this_alive = NULL;
8557                         gboolean pass_vtable = FALSE;
8558                         gboolean pass_mrgctx = FALSE;
8559                         MonoInst *vtable_arg = NULL;
8560                         gboolean check_this = FALSE;
8561                         gboolean supported_tail_call = FALSE;
8562                         gboolean tail_call = FALSE;
8563                         gboolean need_seq_point = FALSE;
8564                         guint32 call_opcode = *ip;
8565                         gboolean emit_widen = TRUE;
8566                         gboolean push_res = TRUE;
8567                         gboolean skip_ret = FALSE;
8568                         gboolean delegate_invoke = FALSE;
8569                         gboolean direct_icall = FALSE;
8570                         gboolean constrained_partial_call = FALSE;
8571                         MonoMethod *cil_method;
8572
8573                         CHECK_OPSIZE (5);
8574                         token = read32 (ip + 1);
8575
8576                         ins = NULL;
8577
8578                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8579                         CHECK_CFG_ERROR;
8580
8581                         cil_method = cmethod;
8582                                 
8583                         if (constrained_class) {
8584                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8585                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8586                                                 g_assert (!cmethod->klass->valuetype);
8587                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8588                                                         constrained_partial_call = TRUE;
8589                                         }
8590                                 }
8591
8592                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8593                                         if (cfg->verbose_level > 2)
8594                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8595                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8596                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8597                                                   cfg->gshared)) {
8598                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8599                                                 CHECK_CFG_ERROR;
8600                                         }
8601                                 } else {
8602                                         if (cfg->verbose_level > 2)
8603                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8604
8605                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8606                                                 /* 
8607                                                  * This is needed since get_method_constrained can't find 
8608                                                  * the method in klass representing a type var.
8609                                                  * The type var is guaranteed to be a reference type in this
8610                                                  * case.
8611                                                  */
8612                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8613                                                         g_assert (!cmethod->klass->valuetype);
8614                                         } else {
8615                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8616                                                 CHECK_CFG_ERROR;
8617                                         }
8618                                 }
8619
8620                                 if (constrained_class->enumtype && !strcmp (cmethod->name, "GetHashCode")) {
8621                                         /* Use the corresponding method from the base type to avoid boxing */
8622                                         MonoType *base_type = mono_class_enum_basetype (constrained_class);
8623                                         g_assert (base_type);
8624                                         constrained_class = mono_class_from_mono_type (base_type);
8625                                         cmethod = mono_class_get_method_from_name (constrained_class, cmethod->name, 0);
8626                                         g_assert (cmethod);
8627                                 }
8628                         }
8629                                         
8630                         if (!dont_verify && !cfg->skip_visibility) {
8631                                 MonoMethod *target_method = cil_method;
8632                                 if (method->is_inflated) {
8633                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
8634                                         CHECK_CFG_ERROR;
8635                                 }
8636                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8637                                         !mono_method_can_access_method (method, cil_method))
8638                                         emit_method_access_failure (cfg, method, cil_method);
8639                         }
8640
8641                         if (mono_security_core_clr_enabled ())
8642                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8643
8644                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8645                                 /* MS.NET seems to silently convert this to a callvirt */
8646                                 virtual_ = 1;
8647
8648                         {
8649                                 /*
8650                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8651                                  * converts to a callvirt.
8652                                  *
8653                                  * tests/bug-515884.il is an example of this behavior
8654                                  */
8655                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8656                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8657                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8658                                         virtual_ = 1;
8659                         }
8660
8661                         if (!cmethod->klass->inited)
8662                                 if (!mono_class_init (cmethod->klass))
8663                                         TYPE_LOAD_ERROR (cmethod->klass);
8664
8665                         fsig = mono_method_signature (cmethod);
8666                         if (!fsig)
8667                                 LOAD_ERROR;
8668                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8669                                 mini_class_is_system_array (cmethod->klass)) {
8670                                 array_rank = cmethod->klass->rank;
8671                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8672                                 direct_icall = TRUE;
8673                         } else if (fsig->pinvoke) {
8674                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8675                                 fsig = mono_method_signature (wrapper);
8676                         } else if (constrained_class) {
8677                         } else {
8678                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8679                                 CHECK_CFG_ERROR;
8680                         }
8681
8682                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
8683                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
8684
8685                         /* See code below */
8686                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8687                                 MonoBasicBlock *tbb;
8688
8689                                 GET_BBLOCK (cfg, tbb, ip + 5);
8690                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8691                                         /*
8692                                          * We want to extend the try block to cover the call, but we can't do it if the
8693                                          * call is made directly since its followed by an exception check.
8694                                          */
8695                                         direct_icall = FALSE;
8696                                 }
8697                         }
8698
8699                         mono_save_token_info (cfg, image, token, cil_method);
8700
8701                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8702                                 need_seq_point = TRUE;
8703
8704                         /* Don't support calls made using type arguments for now */
8705                         /*
8706                           if (cfg->gsharedvt) {
8707                           if (mini_is_gsharedvt_signature (fsig))
8708                           GSHAREDVT_FAILURE (*ip);
8709                           }
8710                         */
8711
8712                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8713                                 g_assert_not_reached ();
8714
8715                         n = fsig->param_count + fsig->hasthis;
8716
8717                         if (!cfg->gshared && mono_class_is_gtd (cmethod->klass))
8718                                 UNVERIFIED;
8719
8720                         if (!cfg->gshared)
8721                                 g_assert (!mono_method_check_context_used (cmethod));
8722
8723                         CHECK_STACK (n);
8724
8725                         //g_assert (!virtual_ || fsig->hasthis);
8726
8727                         sp -= n;
8728
8729                         /*
8730                          * We have the `constrained.' prefix opcode.
8731                          */
8732                         if (constrained_class) {
8733                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8734                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8735                                                 /* The 'Own method' case below */
8736                                         } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) {
8737                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8738                                         } else {
8739                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8740                                                 CHECK_CFG_EXCEPTION;
8741                                                 g_assert (ins);
8742                                                 goto call_end;
8743                                         }
8744                                 }
8745
8746                                 if (constrained_partial_call) {
8747                                         gboolean need_box = TRUE;
8748
8749                                         /*
8750                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8751                                          * called method is not known at compile time either. The called method could end up being
8752                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8753                                          * to box the receiver.
8754                                          * A simple solution would be to box always and make a normal virtual call, but that would
8755                                          * be bad performance wise.
8756                                          */
8757                                         if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) {
8758                                                 /*
8759                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8760                                                  */
8761                                                 need_box = FALSE;
8762                                         }
8763
8764                                         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)) {
8765                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8766                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8767                                                 ins->klass = constrained_class;
8768                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8769                                                 CHECK_CFG_EXCEPTION;
8770                                         } else if (need_box) {
8771                                                 MonoInst *box_type;
8772                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8773                                                 MonoInst *nonbox_call;
8774
8775                                                 /*
8776                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8777                                                  * if needed.
8778                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8779                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8780                                                  */
8781                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8782
8783                                                 NEW_BBLOCK (cfg, is_ref_bb);
8784                                                 NEW_BBLOCK (cfg, end_bb);
8785
8786                                                 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);
8787                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
8788                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
8789
8790                                                 /* Non-ref case */
8791                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8792
8793                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8794
8795                                                 /* Ref case */
8796                                                 MONO_START_BB (cfg, is_ref_bb);
8797                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8798                                                 ins->klass = constrained_class;
8799                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8800                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8801
8802                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8803
8804                                                 MONO_START_BB (cfg, end_bb);
8805                                                 cfg->cbb = end_bb;
8806
8807                                                 nonbox_call->dreg = ins->dreg;
8808                                                 goto call_end;
8809                                         } else {
8810                                                 g_assert (mono_class_is_interface (cmethod->klass));
8811                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8812                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8813                                                 goto call_end;
8814                                         }
8815                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8816                                         /*
8817                                          * The type parameter is instantiated as a valuetype,
8818                                          * but that type doesn't override the method we're
8819                                          * calling, so we need to box `this'.
8820                                          */
8821                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8822                                         ins->klass = constrained_class;
8823                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8824                                         CHECK_CFG_EXCEPTION;
8825                                 } else if (!constrained_class->valuetype) {
8826                                         int dreg = alloc_ireg_ref (cfg);
8827
8828                                         /*
8829                                          * The type parameter is instantiated as a reference
8830                                          * type.  We have a managed pointer on the stack, so
8831                                          * we need to dereference it here.
8832                                          */
8833                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8834                                         ins->type = STACK_OBJ;
8835                                         sp [0] = ins;
8836                                 } else {
8837                                         if (cmethod->klass->valuetype) {
8838                                                 /* Own method */
8839                                         } else {
8840                                                 /* Interface method */
8841                                                 int ioffset, slot;
8842
8843                                                 mono_class_setup_vtable (constrained_class);
8844                                                 CHECK_TYPELOAD (constrained_class);
8845                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8846                                                 if (ioffset == -1)
8847                                                         TYPE_LOAD_ERROR (constrained_class);
8848                                                 slot = mono_method_get_vtable_slot (cmethod);
8849                                                 if (slot == -1)
8850                                                         TYPE_LOAD_ERROR (cmethod->klass);
8851                                                 cmethod = constrained_class->vtable [ioffset + slot];
8852
8853                                                 if (cmethod->klass == mono_defaults.enum_class) {
8854                                                         /* Enum implements some interfaces, so treat this as the first case */
8855                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8856                                                         ins->klass = constrained_class;
8857                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8858                                                         CHECK_CFG_EXCEPTION;
8859                                                 }
8860                                         }
8861                                         virtual_ = 0;
8862                                 }
8863                                 constrained_class = NULL;
8864                         }
8865
8866                         if (check_call_signature (cfg, fsig, sp))
8867                                 UNVERIFIED;
8868
8869                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8870                                 delegate_invoke = TRUE;
8871
8872                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8873                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8874                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8875                                         emit_widen = FALSE;
8876                                 }
8877
8878                                 goto call_end;
8879                         }
8880
8881                         /* 
8882                          * If the callee is a shared method, then its static cctor
8883                          * might not get called after the call was patched.
8884                          */
8885                         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)) {
8886                                 emit_class_init (cfg, cmethod->klass);
8887                                 CHECK_TYPELOAD (cmethod->klass);
8888                         }
8889
8890                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8891
8892                         if (cfg->gshared) {
8893                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8894
8895                                 context_used = mini_method_check_context_used (cfg, cmethod);
8896
8897                                 if (context_used && mono_class_is_interface (cmethod->klass)) {
8898                                         /* Generic method interface
8899                                            calls are resolved via a
8900                                            helper function and don't
8901                                            need an imt. */
8902                                         if (!cmethod_context || !cmethod_context->method_inst)
8903                                                 pass_imt_from_rgctx = TRUE;
8904                                 }
8905
8906                                 /*
8907                                  * If a shared method calls another
8908                                  * shared method then the caller must
8909                                  * have a generic sharing context
8910                                  * because the magic trampoline
8911                                  * requires it.  FIXME: We shouldn't
8912                                  * have to force the vtable/mrgctx
8913                                  * variable here.  Instead there
8914                                  * should be a flag in the cfg to
8915                                  * request a generic sharing context.
8916                                  */
8917                                 if (context_used &&
8918                                                 ((cfg->method->flags & METHOD_ATTRIBUTE_STATIC) || cfg->method->klass->valuetype))
8919                                         mono_get_vtable_var (cfg);
8920                         }
8921
8922                         if (pass_vtable) {
8923                                 if (context_used) {
8924                                         vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8925                                 } else {
8926                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8927
8928                                         CHECK_TYPELOAD (cmethod->klass);
8929                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8930                                 }
8931                         }
8932
8933                         if (pass_mrgctx) {
8934                                 g_assert (!vtable_arg);
8935
8936                                 if (!cfg->compile_aot) {
8937                                         /* 
8938                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8939                                          * for type load errors before.
8940                                          */
8941                                         mono_class_setup_vtable (cmethod->klass);
8942                                         CHECK_TYPELOAD (cmethod->klass);
8943                                 }
8944
8945                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8946
8947                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8948                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8949                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8950                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8951                                         if (virtual_)
8952                                                 check_this = TRUE;
8953                                         virtual_ = 0;
8954                                 }
8955                         }
8956
8957                         if (pass_imt_from_rgctx) {
8958                                 g_assert (!pass_vtable);
8959
8960                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8961                                         cmethod, MONO_RGCTX_INFO_METHOD);
8962                         }
8963
8964                         if (check_this)
8965                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8966
8967                         /* Calling virtual generic methods */
8968                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
8969                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8970                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8971                             fsig->generic_param_count && 
8972                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
8973                                 !cfg->llvm_only) {
8974                                 MonoInst *this_temp, *this_arg_temp, *store;
8975                                 MonoInst *iargs [4];
8976
8977                                 g_assert (fsig->is_inflated);
8978
8979                                 /* Prevent inlining of methods that contain indirect calls */
8980                                 INLINE_FAILURE ("virtual generic call");
8981
8982                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8983                                         GSHAREDVT_FAILURE (*ip);
8984
8985                                 if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
8986                                         g_assert (!imt_arg);
8987                                         if (!context_used)
8988                                                 g_assert (cmethod->is_inflated);
8989                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8990                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8991                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8992                                 } else {
8993                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8994                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8995                                         MONO_ADD_INS (cfg->cbb, store);
8996
8997                                         /* FIXME: This should be a managed pointer */
8998                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8999
9000                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9001                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9002                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9003                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9004                                         addr = mono_emit_jit_icall (cfg,
9005                                                                                                 mono_helper_compile_generic_method, iargs);
9006
9007                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9008
9009                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9010                                 }
9011
9012                                 goto call_end;
9013                         }
9014
9015                         /*
9016                          * Implement a workaround for the inherent races involved in locking:
9017                          * Monitor.Enter ()
9018                          * try {
9019                          * } finally {
9020                          *    Monitor.Exit ()
9021                          * }
9022                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9023                          * try block, the Exit () won't be executed, see:
9024                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9025                          * To work around this, we extend such try blocks to include the last x bytes
9026                          * of the Monitor.Enter () call.
9027                          */
9028                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9029                                 MonoBasicBlock *tbb;
9030
9031                                 GET_BBLOCK (cfg, tbb, ip + 5);
9032                                 /* 
9033                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9034                                  * from Monitor.Enter like ArgumentNullException.
9035                                  */
9036                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9037                                         /* Mark this bblock as needing to be extended */
9038                                         tbb->extend_try_block = TRUE;
9039                                 }
9040                         }
9041
9042                         /* Conversion to a JIT intrinsic */
9043                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9044                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9045                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9046                                         emit_widen = FALSE;
9047                                 }
9048                                 goto call_end;
9049                         }
9050                         CHECK_CFG_ERROR;
9051                         
9052                         /* Inlining */
9053                         if ((cfg->opt & MONO_OPT_INLINE) &&
9054                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9055                             mono_method_check_inlining (cfg, cmethod)) {
9056                                 int costs;
9057                                 gboolean always = FALSE;
9058
9059                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9060                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9061                                         /* Prevent inlining of methods that call wrappers */
9062                                         INLINE_FAILURE ("wrapper call");
9063                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9064                                         always = TRUE;
9065                                 }
9066
9067                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9068                                 if (costs) {
9069                                         cfg->real_offset += 5;
9070
9071                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9072                                                 /* *sp is already set by inline_method */
9073                                                 sp++;
9074                                                 push_res = FALSE;
9075                                         }
9076
9077                                         inline_costs += costs;
9078
9079                                         goto call_end;
9080                                 }
9081                         }
9082
9083                         /* Tail recursion elimination */
9084                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9085                                 gboolean has_vtargs = FALSE;
9086                                 int i;
9087
9088                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9089                                 INLINE_FAILURE ("tail call");
9090
9091                                 /* keep it simple */
9092                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9093                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9094                                                 has_vtargs = TRUE;
9095                                 }
9096
9097                                 if (!has_vtargs) {
9098                                         if (need_seq_point) {
9099                                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9100                                                 need_seq_point = FALSE;
9101                                         }
9102                                         for (i = 0; i < n; ++i)
9103                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9104                                         MONO_INST_NEW (cfg, ins, OP_BR);
9105                                         MONO_ADD_INS (cfg->cbb, ins);
9106                                         tblock = start_bblock->out_bb [0];
9107                                         link_bblock (cfg, cfg->cbb, tblock);
9108                                         ins->inst_target_bb = tblock;
9109                                         start_new_bblock = 1;
9110
9111                                         /* skip the CEE_RET, too */
9112                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9113                                                 skip_ret = TRUE;
9114                                         push_res = FALSE;
9115                                         goto call_end;
9116                                 }
9117                         }
9118
9119                         inline_costs += 10 * num_calls++;
9120
9121                         /*
9122                          * Synchronized wrappers.
9123                          * Its hard to determine where to replace a method with its synchronized
9124                          * wrapper without causing an infinite recursion. The current solution is
9125                          * to add the synchronized wrapper in the trampolines, and to
9126                          * change the called method to a dummy wrapper, and resolve that wrapper
9127                          * to the real method in mono_jit_compile_method ().
9128                          */
9129                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9130                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9131                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9132                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9133                         }
9134
9135                         /*
9136                          * Making generic calls out of gsharedvt methods.
9137                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9138                          * patching gshared method addresses into a gsharedvt method.
9139                          */
9140                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) &&
9141                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9142                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9143                                 MonoRgctxInfoType info_type;
9144
9145                                 if (virtual_) {
9146                                         //if (mono_class_is_interface (cmethod->klass))
9147                                                 //GSHAREDVT_FAILURE (*ip);
9148                                         // disable for possible remoting calls
9149                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9150                                                 GSHAREDVT_FAILURE (*ip);
9151                                         if (fsig->generic_param_count) {
9152                                                 /* virtual generic call */
9153                                                 g_assert (!imt_arg);
9154                                                 /* Same as the virtual generic case above */
9155                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9156                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9157                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9158                                                 vtable_arg = NULL;
9159                                         } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) {
9160                                                 /* This can happen when we call a fully instantiated iface method */
9161                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9162                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9163                                                 vtable_arg = NULL;
9164                                         }
9165                                 }
9166
9167                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9168                                         keep_this_alive = sp [0];
9169
9170                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9171                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9172                                 else
9173                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9174                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9175
9176                                 if (cfg->llvm_only) {
9177                                         // FIXME: Avoid initializing vtable_arg
9178                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9179                                 } else {
9180                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9181                                 }
9182                                 goto call_end;
9183                         }
9184
9185                         /* Generic sharing */
9186
9187                         /*
9188                          * Use this if the callee is gsharedvt sharable too, since
9189                          * at runtime we might find an instantiation so the call cannot
9190                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9191                          */
9192                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9193                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9194                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9195                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9196                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9197                                 INLINE_FAILURE ("gshared");
9198
9199                                 g_assert (cfg->gshared && cmethod);
9200                                 g_assert (!addr);
9201
9202                                 /*
9203                                  * We are compiling a call to a
9204                                  * generic method from shared code,
9205                                  * which means that we have to look up
9206                                  * the method in the rgctx and do an
9207                                  * indirect call.
9208                                  */
9209                                 if (fsig->hasthis)
9210                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9211
9212                                 if (cfg->llvm_only) {
9213                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9214                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9215                                         else
9216                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9217                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9218                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9219                                 } else {
9220                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9221                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9222                                 }
9223                                 goto call_end;
9224                         }
9225
9226                         /* Direct calls to icalls */
9227                         if (direct_icall) {
9228                                 MonoMethod *wrapper;
9229                                 int costs;
9230
9231                                 /* Inline the wrapper */
9232                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9233
9234                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9235                                 g_assert (costs > 0);
9236                                 cfg->real_offset += 5;
9237
9238                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9239                                         /* *sp is already set by inline_method */
9240                                         sp++;
9241                                         push_res = FALSE;
9242                                 }
9243
9244                                 inline_costs += costs;
9245
9246                                 goto call_end;
9247                         }
9248                                         
9249                         /* Array methods */
9250                         if (array_rank) {
9251                                 MonoInst *addr;
9252
9253                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9254                                         MonoInst *val = sp [fsig->param_count];
9255
9256                                         if (val->type == STACK_OBJ) {
9257                                                 MonoInst *iargs [2];
9258
9259                                                 iargs [0] = sp [0];
9260                                                 iargs [1] = val;
9261                                                 
9262                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9263                                         }
9264                                         
9265                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9266                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9267                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
9268                                                 emit_write_barrier (cfg, addr, val);
9269                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9270                                                 GSHAREDVT_FAILURE (*ip);
9271                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9272                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9273
9274                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9275                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9276                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9277                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9278                                         CHECK_TYPELOAD (cmethod->klass);
9279                                         
9280                                         readonly = FALSE;
9281                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9282                                         ins = addr;
9283                                 } else {
9284                                         g_assert_not_reached ();
9285                                 }
9286
9287                                 emit_widen = FALSE;
9288                                 goto call_end;
9289                         }
9290
9291                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9292                         if (ins)
9293                                 goto call_end;
9294
9295                         /* Tail prefix / tail call optimization */
9296
9297                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9298                         /* FIXME: runtime generic context pointer for jumps? */
9299                         /* FIXME: handle this for generic sharing eventually */
9300                         if ((ins_flag & MONO_INST_TAILCALL) &&
9301                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9302                                 supported_tail_call = TRUE;
9303
9304                         if (supported_tail_call) {
9305                                 MonoCallInst *call;
9306
9307                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9308                                 INLINE_FAILURE ("tail call");
9309
9310                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9311
9312                                 if (cfg->backend->have_op_tail_call) {
9313                                         /* Handle tail calls similarly to normal calls */
9314                                         tail_call = TRUE;
9315                                 } else {
9316                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9317
9318                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9319                                         call->tail_call = TRUE;
9320                                         call->method = cmethod;
9321                                         call->signature = mono_method_signature (cmethod);
9322
9323                                         /*
9324                                          * We implement tail calls by storing the actual arguments into the 
9325                                          * argument variables, then emitting a CEE_JMP.
9326                                          */
9327                                         for (i = 0; i < n; ++i) {
9328                                                 /* Prevent argument from being register allocated */
9329                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9330                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9331                                         }
9332                                         ins = (MonoInst*)call;
9333                                         ins->inst_p0 = cmethod;
9334                                         ins->inst_p1 = arg_array [0];
9335                                         MONO_ADD_INS (cfg->cbb, ins);
9336                                         link_bblock (cfg, cfg->cbb, end_bblock);
9337                                         start_new_bblock = 1;
9338
9339                                         // FIXME: Eliminate unreachable epilogs
9340
9341                                         /*
9342                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9343                                          * only reachable from this call.
9344                                          */
9345                                         GET_BBLOCK (cfg, tblock, ip + 5);
9346                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9347                                                 skip_ret = TRUE;
9348                                         push_res = FALSE;
9349
9350                                         goto call_end;
9351                                 }
9352                         }
9353
9354                         /*
9355                          * Virtual calls in llvm-only mode.
9356                          */
9357                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9358                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9359                                 goto call_end;
9360                         }
9361
9362                         /* Common call */
9363                         if (!(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
9364                                 INLINE_FAILURE ("call");
9365                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9366                                                                                           imt_arg, vtable_arg);
9367
9368                         if (tail_call && !cfg->llvm_only) {
9369                                 link_bblock (cfg, cfg->cbb, end_bblock);
9370                                 start_new_bblock = 1;
9371
9372                                 // FIXME: Eliminate unreachable epilogs
9373
9374                                 /*
9375                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9376                                  * only reachable from this call.
9377                                  */
9378                                 GET_BBLOCK (cfg, tblock, ip + 5);
9379                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9380                                         skip_ret = TRUE;
9381                                 push_res = FALSE;
9382                         }
9383
9384                         call_end:
9385
9386                         /* End of call, INS should contain the result of the call, if any */
9387
9388                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9389                                 g_assert (ins);
9390                                 if (emit_widen)
9391                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9392                                 else
9393                                         *sp++ = ins;
9394                         }
9395
9396                         if (keep_this_alive) {
9397                                 MonoInst *dummy_use;
9398
9399                                 /* See mono_emit_method_call_full () */
9400                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9401                         }
9402
9403                         if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
9404                                 /*
9405                                  * Clang can convert these calls to tail calls which screw up the stack
9406                                  * walk. This happens even when the -fno-optimize-sibling-calls
9407                                  * option is passed to clang.
9408                                  * Work around this by emitting a dummy call.
9409                                  */
9410                                 mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
9411                         }
9412
9413                         CHECK_CFG_EXCEPTION;
9414
9415                         ip += 5;
9416                         if (skip_ret) {
9417                                 g_assert (*ip == CEE_RET);
9418                                 ip += 1;
9419                         }
9420                         ins_flag = 0;
9421                         constrained_class = NULL;
9422                         if (need_seq_point)
9423                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9424                         break;
9425                 }
9426                 case CEE_RET:
9427                         if (cfg->method != method) {
9428                                 /* return from inlined method */
9429                                 /* 
9430                                  * If in_count == 0, that means the ret is unreachable due to
9431                                  * being preceeded by a throw. In that case, inline_method () will
9432                                  * handle setting the return value 
9433                                  * (test case: test_0_inline_throw ()).
9434                                  */
9435                                 if (return_var && cfg->cbb->in_count) {
9436                                         MonoType *ret_type = mono_method_signature (method)->ret;
9437
9438                                         MonoInst *store;
9439                                         CHECK_STACK (1);
9440                                         --sp;
9441
9442                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9443                                                 UNVERIFIED;
9444
9445                                         //g_assert (returnvar != -1);
9446                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9447                                         cfg->ret_var_set = TRUE;
9448                                 } 
9449                         } else {
9450                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9451
9452                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9453                                         emit_pop_lmf (cfg);
9454
9455                                 if (cfg->ret) {
9456                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9457
9458                                         if (seq_points && !sym_seq_points) {
9459                                                 /* 
9460                                                  * Place a seq point here too even through the IL stack is not
9461                                                  * empty, so a step over on
9462                                                  * call <FOO>
9463                                                  * ret
9464                                                  * will work correctly.
9465                                                  */
9466                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9467                                                 MONO_ADD_INS (cfg->cbb, ins);
9468                                         }
9469
9470                                         g_assert (!return_var);
9471                                         CHECK_STACK (1);
9472                                         --sp;
9473
9474                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9475                                                 UNVERIFIED;
9476
9477                                         emit_setret (cfg, *sp);
9478                                 }
9479                         }
9480                         if (sp != stack_start)
9481                                 UNVERIFIED;
9482                         MONO_INST_NEW (cfg, ins, OP_BR);
9483                         ip++;
9484                         ins->inst_target_bb = end_bblock;
9485                         MONO_ADD_INS (cfg->cbb, ins);
9486                         link_bblock (cfg, cfg->cbb, end_bblock);
9487                         start_new_bblock = 1;
9488                         break;
9489                 case CEE_BR_S:
9490                         CHECK_OPSIZE (2);
9491                         MONO_INST_NEW (cfg, ins, OP_BR);
9492                         ip++;
9493                         target = ip + 1 + (signed char)(*ip);
9494                         ++ip;
9495                         GET_BBLOCK (cfg, tblock, target);
9496                         link_bblock (cfg, cfg->cbb, tblock);
9497                         ins->inst_target_bb = tblock;
9498                         if (sp != stack_start) {
9499                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9500                                 sp = stack_start;
9501                                 CHECK_UNVERIFIABLE (cfg);
9502                         }
9503                         MONO_ADD_INS (cfg->cbb, ins);
9504                         start_new_bblock = 1;
9505                         inline_costs += BRANCH_COST;
9506                         break;
9507                 case CEE_BEQ_S:
9508                 case CEE_BGE_S:
9509                 case CEE_BGT_S:
9510                 case CEE_BLE_S:
9511                 case CEE_BLT_S:
9512                 case CEE_BNE_UN_S:
9513                 case CEE_BGE_UN_S:
9514                 case CEE_BGT_UN_S:
9515                 case CEE_BLE_UN_S:
9516                 case CEE_BLT_UN_S:
9517                         CHECK_OPSIZE (2);
9518                         CHECK_STACK (2);
9519                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9520                         ip++;
9521                         target = ip + 1 + *(signed char*)ip;
9522                         ip++;
9523
9524                         ADD_BINCOND (NULL);
9525
9526                         sp = stack_start;
9527                         inline_costs += BRANCH_COST;
9528                         break;
9529                 case CEE_BR:
9530                         CHECK_OPSIZE (5);
9531                         MONO_INST_NEW (cfg, ins, OP_BR);
9532                         ip++;
9533
9534                         target = ip + 4 + (gint32)read32(ip);
9535                         ip += 4;
9536                         GET_BBLOCK (cfg, tblock, target);
9537                         link_bblock (cfg, cfg->cbb, tblock);
9538                         ins->inst_target_bb = tblock;
9539                         if (sp != stack_start) {
9540                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9541                                 sp = stack_start;
9542                                 CHECK_UNVERIFIABLE (cfg);
9543                         }
9544
9545                         MONO_ADD_INS (cfg->cbb, ins);
9546
9547                         start_new_bblock = 1;
9548                         inline_costs += BRANCH_COST;
9549                         break;
9550                 case CEE_BRFALSE_S:
9551                 case CEE_BRTRUE_S:
9552                 case CEE_BRFALSE:
9553                 case CEE_BRTRUE: {
9554                         MonoInst *cmp;
9555                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9556                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9557                         guint32 opsize = is_short ? 1 : 4;
9558
9559                         CHECK_OPSIZE (opsize);
9560                         CHECK_STACK (1);
9561                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9562                                 UNVERIFIED;
9563                         ip ++;
9564                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9565                         ip += opsize;
9566
9567                         sp--;
9568
9569                         GET_BBLOCK (cfg, tblock, target);
9570                         link_bblock (cfg, cfg->cbb, tblock);
9571                         GET_BBLOCK (cfg, tblock, ip);
9572                         link_bblock (cfg, cfg->cbb, tblock);
9573
9574                         if (sp != stack_start) {
9575                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9576                                 CHECK_UNVERIFIABLE (cfg);
9577                         }
9578
9579                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9580                         cmp->sreg1 = sp [0]->dreg;
9581                         type_from_op (cfg, cmp, sp [0], NULL);
9582                         CHECK_TYPE (cmp);
9583
9584 #if SIZEOF_REGISTER == 4
9585                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9586                                 /* Convert it to OP_LCOMPARE */
9587                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9588                                 ins->type = STACK_I8;
9589                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9590                                 ins->inst_l = 0;
9591                                 MONO_ADD_INS (cfg->cbb, ins);
9592                                 cmp->opcode = OP_LCOMPARE;
9593                                 cmp->sreg2 = ins->dreg;
9594                         }
9595 #endif
9596                         MONO_ADD_INS (cfg->cbb, cmp);
9597
9598                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9599                         type_from_op (cfg, ins, sp [0], NULL);
9600                         MONO_ADD_INS (cfg->cbb, ins);
9601                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9602                         GET_BBLOCK (cfg, tblock, target);
9603                         ins->inst_true_bb = tblock;
9604                         GET_BBLOCK (cfg, tblock, ip);
9605                         ins->inst_false_bb = tblock;
9606                         start_new_bblock = 2;
9607
9608                         sp = stack_start;
9609                         inline_costs += BRANCH_COST;
9610                         break;
9611                 }
9612                 case CEE_BEQ:
9613                 case CEE_BGE:
9614                 case CEE_BGT:
9615                 case CEE_BLE:
9616                 case CEE_BLT:
9617                 case CEE_BNE_UN:
9618                 case CEE_BGE_UN:
9619                 case CEE_BGT_UN:
9620                 case CEE_BLE_UN:
9621                 case CEE_BLT_UN:
9622                         CHECK_OPSIZE (5);
9623                         CHECK_STACK (2);
9624                         MONO_INST_NEW (cfg, ins, *ip);
9625                         ip++;
9626                         target = ip + 4 + (gint32)read32(ip);
9627                         ip += 4;
9628
9629                         ADD_BINCOND (NULL);
9630
9631                         sp = stack_start;
9632                         inline_costs += BRANCH_COST;
9633                         break;
9634                 case CEE_SWITCH: {
9635                         MonoInst *src1;
9636                         MonoBasicBlock **targets;
9637                         MonoBasicBlock *default_bblock;
9638                         MonoJumpInfoBBTable *table;
9639                         int offset_reg = alloc_preg (cfg);
9640                         int target_reg = alloc_preg (cfg);
9641                         int table_reg = alloc_preg (cfg);
9642                         int sum_reg = alloc_preg (cfg);
9643                         gboolean use_op_switch;
9644
9645                         CHECK_OPSIZE (5);
9646                         CHECK_STACK (1);
9647                         n = read32 (ip + 1);
9648                         --sp;
9649                         src1 = sp [0];
9650                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9651                                 UNVERIFIED;
9652
9653                         ip += 5;
9654                         CHECK_OPSIZE (n * sizeof (guint32));
9655                         target = ip + n * sizeof (guint32);
9656
9657                         GET_BBLOCK (cfg, default_bblock, target);
9658                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9659
9660                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9661                         for (i = 0; i < n; ++i) {
9662                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9663                                 targets [i] = tblock;
9664                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9665                                 ip += 4;
9666                         }
9667
9668                         if (sp != stack_start) {
9669                                 /* 
9670                                  * Link the current bb with the targets as well, so handle_stack_args
9671                                  * will set their in_stack correctly.
9672                                  */
9673                                 link_bblock (cfg, cfg->cbb, default_bblock);
9674                                 for (i = 0; i < n; ++i)
9675                                         link_bblock (cfg, cfg->cbb, targets [i]);
9676
9677                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9678                                 sp = stack_start;
9679                                 CHECK_UNVERIFIABLE (cfg);
9680
9681                                 /* Undo the links */
9682                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9683                                 for (i = 0; i < n; ++i)
9684                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9685                         }
9686
9687                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9688                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9689
9690                         for (i = 0; i < n; ++i)
9691                                 link_bblock (cfg, cfg->cbb, targets [i]);
9692
9693                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9694                         table->table = targets;
9695                         table->table_size = n;
9696
9697                         use_op_switch = FALSE;
9698 #ifdef TARGET_ARM
9699                         /* ARM implements SWITCH statements differently */
9700                         /* FIXME: Make it use the generic implementation */
9701                         if (!cfg->compile_aot)
9702                                 use_op_switch = TRUE;
9703 #endif
9704
9705                         if (COMPILE_LLVM (cfg))
9706                                 use_op_switch = TRUE;
9707
9708                         cfg->cbb->has_jump_table = 1;
9709
9710                         if (use_op_switch) {
9711                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9712                                 ins->sreg1 = src1->dreg;
9713                                 ins->inst_p0 = table;
9714                                 ins->inst_many_bb = targets;
9715                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
9716                                 MONO_ADD_INS (cfg->cbb, ins);
9717                         } else {
9718                                 if (sizeof (gpointer) == 8)
9719                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9720                                 else
9721                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9722
9723 #if SIZEOF_REGISTER == 8
9724                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9725                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9726 #endif
9727
9728                                 if (cfg->compile_aot) {
9729                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9730                                 } else {
9731                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9732                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9733                                         ins->inst_p0 = table;
9734                                         ins->dreg = table_reg;
9735                                         MONO_ADD_INS (cfg->cbb, ins);
9736                                 }
9737
9738                                 /* FIXME: Use load_memindex */
9739                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9740                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9741                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9742                         }
9743                         start_new_bblock = 1;
9744                         inline_costs += (BRANCH_COST * 2);
9745                         break;
9746                 }
9747                 case CEE_LDIND_I1:
9748                 case CEE_LDIND_U1:
9749                 case CEE_LDIND_I2:
9750                 case CEE_LDIND_U2:
9751                 case CEE_LDIND_I4:
9752                 case CEE_LDIND_U4:
9753                 case CEE_LDIND_I8:
9754                 case CEE_LDIND_I:
9755                 case CEE_LDIND_R4:
9756                 case CEE_LDIND_R8:
9757                 case CEE_LDIND_REF:
9758                         CHECK_STACK (1);
9759                         --sp;
9760
9761                         switch (*ip) {
9762                         case CEE_LDIND_R4:
9763                         case CEE_LDIND_R8:
9764                                 dreg = alloc_freg (cfg);
9765                                 break;
9766                         case CEE_LDIND_I8:
9767                                 dreg = alloc_lreg (cfg);
9768                                 break;
9769                         case CEE_LDIND_REF:
9770                                 dreg = alloc_ireg_ref (cfg);
9771                                 break;
9772                         default:
9773                                 dreg = alloc_preg (cfg);
9774                         }
9775
9776                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9777                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9778                         if (*ip == CEE_LDIND_R4)
9779                                 ins->type = cfg->r4_stack_type;
9780                         ins->flags |= ins_flag;
9781                         MONO_ADD_INS (cfg->cbb, ins);
9782                         *sp++ = ins;
9783                         if (ins_flag & MONO_INST_VOLATILE) {
9784                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9785                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9786                         }
9787                         ins_flag = 0;
9788                         ++ip;
9789                         break;
9790                 case CEE_STIND_REF:
9791                 case CEE_STIND_I1:
9792                 case CEE_STIND_I2:
9793                 case CEE_STIND_I4:
9794                 case CEE_STIND_I8:
9795                 case CEE_STIND_R4:
9796                 case CEE_STIND_R8:
9797                 case CEE_STIND_I:
9798                         CHECK_STACK (2);
9799                         sp -= 2;
9800
9801                         if (ins_flag & MONO_INST_VOLATILE) {
9802                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9803                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9804                         }
9805
9806                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9807                         ins->flags |= ins_flag;
9808                         ins_flag = 0;
9809
9810                         MONO_ADD_INS (cfg->cbb, ins);
9811
9812                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
9813                                 emit_write_barrier (cfg, sp [0], sp [1]);
9814
9815                         inline_costs += 1;
9816                         ++ip;
9817                         break;
9818
9819                 case CEE_MUL:
9820                         CHECK_STACK (2);
9821
9822                         MONO_INST_NEW (cfg, ins, (*ip));
9823                         sp -= 2;
9824                         ins->sreg1 = sp [0]->dreg;
9825                         ins->sreg2 = sp [1]->dreg;
9826                         type_from_op (cfg, ins, sp [0], sp [1]);
9827                         CHECK_TYPE (ins);
9828                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9829
9830                         /* Use the immediate opcodes if possible */
9831                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9832                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9833                                 if (imm_opcode != -1) {
9834                                         ins->opcode = imm_opcode;
9835                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9836                                         ins->sreg2 = -1;
9837
9838                                         NULLIFY_INS (sp [1]);
9839                                 }
9840                         }
9841
9842                         MONO_ADD_INS ((cfg)->cbb, (ins));
9843
9844                         *sp++ = mono_decompose_opcode (cfg, ins);
9845                         ip++;
9846                         break;
9847                 case CEE_ADD:
9848                 case CEE_SUB:
9849                 case CEE_DIV:
9850                 case CEE_DIV_UN:
9851                 case CEE_REM:
9852                 case CEE_REM_UN:
9853                 case CEE_AND:
9854                 case CEE_OR:
9855                 case CEE_XOR:
9856                 case CEE_SHL:
9857                 case CEE_SHR:
9858                 case CEE_SHR_UN:
9859                         CHECK_STACK (2);
9860
9861                         MONO_INST_NEW (cfg, ins, (*ip));
9862                         sp -= 2;
9863                         ins->sreg1 = sp [0]->dreg;
9864                         ins->sreg2 = sp [1]->dreg;
9865                         type_from_op (cfg, ins, sp [0], sp [1]);
9866                         CHECK_TYPE (ins);
9867                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9868                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9869
9870                         /* FIXME: Pass opcode to is_inst_imm */
9871
9872                         /* Use the immediate opcodes if possible */
9873                         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)) {
9874                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9875                                 if (imm_opcode != -1) {
9876                                         ins->opcode = imm_opcode;
9877                                         if (sp [1]->opcode == OP_I8CONST) {
9878 #if SIZEOF_REGISTER == 8
9879                                                 ins->inst_imm = sp [1]->inst_l;
9880 #else
9881                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9882                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9883 #endif
9884                                         }
9885                                         else
9886                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9887                                         ins->sreg2 = -1;
9888
9889                                         /* Might be followed by an instruction added by add_widen_op */
9890                                         if (sp [1]->next == NULL)
9891                                                 NULLIFY_INS (sp [1]);
9892                                 }
9893                         }
9894                         MONO_ADD_INS ((cfg)->cbb, (ins));
9895
9896                         *sp++ = mono_decompose_opcode (cfg, ins);
9897                         ip++;
9898                         break;
9899                 case CEE_NEG:
9900                 case CEE_NOT:
9901                 case CEE_CONV_I1:
9902                 case CEE_CONV_I2:
9903                 case CEE_CONV_I4:
9904                 case CEE_CONV_R4:
9905                 case CEE_CONV_R8:
9906                 case CEE_CONV_U4:
9907                 case CEE_CONV_I8:
9908                 case CEE_CONV_U8:
9909                 case CEE_CONV_OVF_I8:
9910                 case CEE_CONV_OVF_U8:
9911                 case CEE_CONV_R_UN:
9912                         CHECK_STACK (1);
9913
9914                         /* Special case this earlier so we have long constants in the IR */
9915                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9916                                 int data = sp [-1]->inst_c0;
9917                                 sp [-1]->opcode = OP_I8CONST;
9918                                 sp [-1]->type = STACK_I8;
9919 #if SIZEOF_REGISTER == 8
9920                                 if ((*ip) == CEE_CONV_U8)
9921                                         sp [-1]->inst_c0 = (guint32)data;
9922                                 else
9923                                         sp [-1]->inst_c0 = data;
9924 #else
9925                                 sp [-1]->inst_ls_word = data;
9926                                 if ((*ip) == CEE_CONV_U8)
9927                                         sp [-1]->inst_ms_word = 0;
9928                                 else
9929                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9930 #endif
9931                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9932                         }
9933                         else {
9934                                 ADD_UNOP (*ip);
9935                         }
9936                         ip++;
9937                         break;
9938                 case CEE_CONV_OVF_I4:
9939                 case CEE_CONV_OVF_I1:
9940                 case CEE_CONV_OVF_I2:
9941                 case CEE_CONV_OVF_I:
9942                 case CEE_CONV_OVF_U:
9943                         CHECK_STACK (1);
9944
9945                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9946                                 ADD_UNOP (CEE_CONV_OVF_I8);
9947                                 ADD_UNOP (*ip);
9948                         } else {
9949                                 ADD_UNOP (*ip);
9950                         }
9951                         ip++;
9952                         break;
9953                 case CEE_CONV_OVF_U1:
9954                 case CEE_CONV_OVF_U2:
9955                 case CEE_CONV_OVF_U4:
9956                         CHECK_STACK (1);
9957
9958                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9959                                 ADD_UNOP (CEE_CONV_OVF_U8);
9960                                 ADD_UNOP (*ip);
9961                         } else {
9962                                 ADD_UNOP (*ip);
9963                         }
9964                         ip++;
9965                         break;
9966                 case CEE_CONV_OVF_I1_UN:
9967                 case CEE_CONV_OVF_I2_UN:
9968                 case CEE_CONV_OVF_I4_UN:
9969                 case CEE_CONV_OVF_I8_UN:
9970                 case CEE_CONV_OVF_U1_UN:
9971                 case CEE_CONV_OVF_U2_UN:
9972                 case CEE_CONV_OVF_U4_UN:
9973                 case CEE_CONV_OVF_U8_UN:
9974                 case CEE_CONV_OVF_I_UN:
9975                 case CEE_CONV_OVF_U_UN:
9976                 case CEE_CONV_U2:
9977                 case CEE_CONV_U1:
9978                 case CEE_CONV_I:
9979                 case CEE_CONV_U:
9980                         CHECK_STACK (1);
9981                         ADD_UNOP (*ip);
9982                         CHECK_CFG_EXCEPTION;
9983                         ip++;
9984                         break;
9985                 case CEE_ADD_OVF:
9986                 case CEE_ADD_OVF_UN:
9987                 case CEE_MUL_OVF:
9988                 case CEE_MUL_OVF_UN:
9989                 case CEE_SUB_OVF:
9990                 case CEE_SUB_OVF_UN:
9991                         CHECK_STACK (2);
9992                         ADD_BINOP (*ip);
9993                         ip++;
9994                         break;
9995                 case CEE_CPOBJ:
9996                         GSHAREDVT_FAILURE (*ip);
9997                         CHECK_OPSIZE (5);
9998                         CHECK_STACK (2);
9999                         token = read32 (ip + 1);
10000                         klass = mini_get_class (method, token, generic_context);
10001                         CHECK_TYPELOAD (klass);
10002                         sp -= 2;
10003                         if (generic_class_is_reference_type (cfg, klass)) {
10004                                 MonoInst *store, *load;
10005                                 int dreg = alloc_ireg_ref (cfg);
10006
10007                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10008                                 load->flags |= ins_flag;
10009                                 MONO_ADD_INS (cfg->cbb, load);
10010
10011                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10012                                 store->flags |= ins_flag;
10013                                 MONO_ADD_INS (cfg->cbb, store);
10014
10015                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10016                                         emit_write_barrier (cfg, sp [0], sp [1]);
10017                         } else {
10018                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10019                         }
10020                         ins_flag = 0;
10021                         ip += 5;
10022                         break;
10023                 case CEE_LDOBJ: {
10024                         int loc_index = -1;
10025                         int stloc_len = 0;
10026
10027                         CHECK_OPSIZE (5);
10028                         CHECK_STACK (1);
10029                         --sp;
10030                         token = read32 (ip + 1);
10031                         klass = mini_get_class (method, token, generic_context);
10032                         CHECK_TYPELOAD (klass);
10033
10034                         /* Optimize the common ldobj+stloc combination */
10035                         switch (ip [5]) {
10036                         case CEE_STLOC_S:
10037                                 loc_index = ip [6];
10038                                 stloc_len = 2;
10039                                 break;
10040                         case CEE_STLOC_0:
10041                         case CEE_STLOC_1:
10042                         case CEE_STLOC_2:
10043                         case CEE_STLOC_3:
10044                                 loc_index = ip [5] - CEE_STLOC_0;
10045                                 stloc_len = 1;
10046                                 break;
10047                         default:
10048                                 break;
10049                         }
10050
10051                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10052                                 CHECK_LOCAL (loc_index);
10053
10054                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10055                                 ins->dreg = cfg->locals [loc_index]->dreg;
10056                                 ins->flags |= ins_flag;
10057                                 ip += 5;
10058                                 ip += stloc_len;
10059                                 if (ins_flag & MONO_INST_VOLATILE) {
10060                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10061                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10062                                 }
10063                                 ins_flag = 0;
10064                                 break;
10065                         }
10066
10067                         /* Optimize the ldobj+stobj combination */
10068                         /* The reference case ends up being a load+store anyway */
10069                         /* Skip this if the operation is volatile. */
10070                         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)) {
10071                                 CHECK_STACK (1);
10072
10073                                 sp --;
10074
10075                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10076
10077                                 ip += 5 + 5;
10078                                 ins_flag = 0;
10079                                 break;
10080                         }
10081
10082                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10083                         ins->flags |= ins_flag;
10084                         *sp++ = ins;
10085
10086                         if (ins_flag & MONO_INST_VOLATILE) {
10087                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10088                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10089                         }
10090
10091                         ip += 5;
10092                         ins_flag = 0;
10093                         inline_costs += 1;
10094                         break;
10095                 }
10096                 case CEE_LDSTR:
10097                         CHECK_STACK_OVF (1);
10098                         CHECK_OPSIZE (5);
10099                         n = read32 (ip + 1);
10100
10101                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10102                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10103                                 ins->type = STACK_OBJ;
10104                                 *sp = ins;
10105                         }
10106                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10107                                 MonoInst *iargs [1];
10108                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10109
10110                                 if (cfg->compile_aot)
10111                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10112                                 else
10113                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10114                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10115                         } else {
10116                                 if (cfg->opt & MONO_OPT_SHARED) {
10117                                         MonoInst *iargs [3];
10118
10119                                         if (cfg->compile_aot) {
10120                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10121                                         }
10122                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10123                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10124                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10125                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10126                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10127                                         CHECK_CFG_ERROR;
10128                                 } else {
10129                                         if (cfg->cbb->out_of_line) {
10130                                                 MonoInst *iargs [2];
10131
10132                                                 if (image == mono_defaults.corlib) {
10133                                                         /* 
10134                                                          * Avoid relocations in AOT and save some space by using a 
10135                                                          * version of helper_ldstr specialized to mscorlib.
10136                                                          */
10137                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10138                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10139                                                 } else {
10140                                                         /* Avoid creating the string object */
10141                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10142                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10143                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10144                                                 }
10145                                         } 
10146                                         else
10147                                         if (cfg->compile_aot) {
10148                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10149                                                 *sp = ins;
10150                                                 MONO_ADD_INS (cfg->cbb, ins);
10151                                         } 
10152                                         else {
10153                                                 NEW_PCONST (cfg, ins, NULL);
10154                                                 ins->type = STACK_OBJ;
10155                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10156                                                 CHECK_CFG_ERROR;
10157                                                 
10158                                                 if (!ins->inst_p0)
10159                                                         OUT_OF_MEMORY_FAILURE;
10160
10161                                                 *sp = ins;
10162                                                 MONO_ADD_INS (cfg->cbb, ins);
10163                                         }
10164                                 }
10165                         }
10166
10167                         sp++;
10168                         ip += 5;
10169                         break;
10170                 case CEE_NEWOBJ: {
10171                         MonoInst *iargs [2];
10172                         MonoMethodSignature *fsig;
10173                         MonoInst this_ins;
10174                         MonoInst *alloc;
10175                         MonoInst *vtable_arg = NULL;
10176
10177                         CHECK_OPSIZE (5);
10178                         token = read32 (ip + 1);
10179                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10180                         CHECK_CFG_ERROR;
10181
10182                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10183                         CHECK_CFG_ERROR;
10184
10185                         mono_save_token_info (cfg, image, token, cmethod);
10186
10187                         if (!mono_class_init (cmethod->klass))
10188                                 TYPE_LOAD_ERROR (cmethod->klass);
10189
10190                         context_used = mini_method_check_context_used (cfg, cmethod);
10191
10192                         if (mono_security_core_clr_enabled ())
10193                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10194
10195                         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)) {
10196                                 emit_class_init (cfg, cmethod->klass);
10197                                 CHECK_TYPELOAD (cmethod->klass);
10198                         }
10199
10200                         /*
10201                         if (cfg->gsharedvt) {
10202                                 if (mini_is_gsharedvt_variable_signature (sig))
10203                                         GSHAREDVT_FAILURE (*ip);
10204                         }
10205                         */
10206
10207                         n = fsig->param_count;
10208                         CHECK_STACK (n);
10209
10210                         /* 
10211                          * Generate smaller code for the common newobj <exception> instruction in
10212                          * argument checking code.
10213                          */
10214                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10215                                 is_exception_class (cmethod->klass) && n <= 2 &&
10216                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10217                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10218                                 MonoInst *iargs [3];
10219
10220                                 sp -= n;
10221
10222                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10223                                 switch (n) {
10224                                 case 0:
10225                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10226                                         break;
10227                                 case 1:
10228                                         iargs [1] = sp [0];
10229                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10230                                         break;
10231                                 case 2:
10232                                         iargs [1] = sp [0];
10233                                         iargs [2] = sp [1];
10234                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10235                                         break;
10236                                 default:
10237                                         g_assert_not_reached ();
10238                                 }
10239
10240                                 ip += 5;
10241                                 inline_costs += 5;
10242                                 break;
10243                         }
10244
10245                         /* move the args to allow room for 'this' in the first position */
10246                         while (n--) {
10247                                 --sp;
10248                                 sp [1] = sp [0];
10249                         }
10250
10251                         /* check_call_signature () requires sp[0] to be set */
10252                         this_ins.type = STACK_OBJ;
10253                         sp [0] = &this_ins;
10254                         if (check_call_signature (cfg, fsig, sp))
10255                                 UNVERIFIED;
10256
10257                         iargs [0] = NULL;
10258
10259                         if (mini_class_is_system_array (cmethod->klass)) {
10260                                 *sp = emit_get_rgctx_method (cfg, context_used,
10261                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10262
10263                                 /* Avoid varargs in the common case */
10264                                 if (fsig->param_count == 1)
10265                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10266                                 else if (fsig->param_count == 2)
10267                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10268                                 else if (fsig->param_count == 3)
10269                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10270                                 else if (fsig->param_count == 4)
10271                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10272                                 else
10273                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10274                         } else if (cmethod->string_ctor) {
10275                                 g_assert (!context_used);
10276                                 g_assert (!vtable_arg);
10277                                 /* we simply pass a null pointer */
10278                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10279                                 /* now call the string ctor */
10280                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10281                         } else {
10282                                 if (cmethod->klass->valuetype) {
10283                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10284                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10285                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10286
10287                                         alloc = NULL;
10288
10289                                         /* 
10290                                          * The code generated by mini_emit_virtual_call () expects
10291                                          * iargs [0] to be a boxed instance, but luckily the vcall
10292                                          * will be transformed into a normal call there.
10293                                          */
10294                                 } else if (context_used) {
10295                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10296                                         *sp = alloc;
10297                                 } else {
10298                                         MonoVTable *vtable = NULL;
10299
10300                                         if (!cfg->compile_aot)
10301                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10302                                         CHECK_TYPELOAD (cmethod->klass);
10303
10304                                         /*
10305                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10306                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10307                                          * As a workaround, we call class cctors before allocating objects.
10308                                          */
10309                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10310                                                 emit_class_init (cfg, cmethod->klass);
10311                                                 if (cfg->verbose_level > 2)
10312                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10313                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10314                                         }
10315
10316                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10317                                         *sp = alloc;
10318                                 }
10319                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10320
10321                                 if (alloc)
10322                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10323
10324                                 /* Now call the actual ctor */
10325                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10326                                 CHECK_CFG_EXCEPTION;
10327                         }
10328
10329                         if (alloc == NULL) {
10330                                 /* Valuetype */
10331                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10332                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10333                                 *sp++= ins;
10334                         } else {
10335                                 *sp++ = alloc;
10336                         }
10337                         
10338                         ip += 5;
10339                         inline_costs += 5;
10340                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10341                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10342                         break;
10343                 }
10344                 case CEE_CASTCLASS:
10345                 case CEE_ISINST: {
10346                         CHECK_STACK (1);
10347                         --sp;
10348                         CHECK_OPSIZE (5);
10349                         token = read32 (ip + 1);
10350                         klass = mini_get_class (method, token, generic_context);
10351                         CHECK_TYPELOAD (klass);
10352                         if (sp [0]->type != STACK_OBJ)
10353                                 UNVERIFIED;
10354
10355                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
10356                         ins->dreg = alloc_preg (cfg);
10357                         ins->sreg1 = (*sp)->dreg;
10358                         ins->klass = klass;
10359                         ins->type = STACK_OBJ;
10360                         MONO_ADD_INS (cfg->cbb, ins);
10361
10362                         CHECK_CFG_EXCEPTION;
10363                         *sp++ = ins;
10364                         ip += 5;
10365
10366                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10367                         break;
10368                 }
10369                 case CEE_UNBOX_ANY: {
10370                         MonoInst *res, *addr;
10371
10372                         CHECK_STACK (1);
10373                         --sp;
10374                         CHECK_OPSIZE (5);
10375                         token = read32 (ip + 1);
10376                         klass = mini_get_class (method, token, generic_context);
10377                         CHECK_TYPELOAD (klass);
10378
10379                         mono_save_token_info (cfg, image, token, klass);
10380
10381                         context_used = mini_class_check_context_used (cfg, klass);
10382
10383                         if (mini_is_gsharedvt_klass (klass)) {
10384                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10385                                 inline_costs += 2;
10386                         } else if (generic_class_is_reference_type (cfg, klass)) {
10387                                 if (MONO_INS_IS_PCONST_NULL (*sp)) {
10388                                         EMIT_NEW_PCONST (cfg, res, NULL);
10389                                         res->type = STACK_OBJ;
10390                                 } else {
10391                                         MONO_INST_NEW (cfg, res, OP_CASTCLASS);
10392                                         res->dreg = alloc_preg (cfg);
10393                                         res->sreg1 = (*sp)->dreg;
10394                                         res->klass = klass;
10395                                         res->type = STACK_OBJ;
10396                                         MONO_ADD_INS (cfg->cbb, res);
10397                                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10398                                 }
10399                         } else if (mono_class_is_nullable (klass)) {
10400                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10401                         } else {
10402                                 addr = handle_unbox (cfg, klass, sp, context_used);
10403                                 /* LDOBJ */
10404                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10405                                 res = ins;
10406                                 inline_costs += 2;
10407                         }
10408
10409                         *sp ++ = res;
10410                         ip += 5;
10411                         break;
10412                 }
10413                 case CEE_BOX: {
10414                         MonoInst *val;
10415                         MonoClass *enum_class;
10416                         MonoMethod *has_flag;
10417
10418                         CHECK_STACK (1);
10419                         --sp;
10420                         val = *sp;
10421                         CHECK_OPSIZE (5);
10422                         token = read32 (ip + 1);
10423                         klass = mini_get_class (method, token, generic_context);
10424                         CHECK_TYPELOAD (klass);
10425
10426                         mono_save_token_info (cfg, image, token, klass);
10427
10428                         context_used = mini_class_check_context_used (cfg, klass);
10429
10430                         if (generic_class_is_reference_type (cfg, klass)) {
10431                                 *sp++ = val;
10432                                 ip += 5;
10433                                 break;
10434                         }
10435
10436                         if (klass == mono_defaults.void_class)
10437                                 UNVERIFIED;
10438                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10439                                 UNVERIFIED;
10440                         /* frequent check in generic code: box (struct), brtrue */
10441
10442                         /*
10443                          * Look for:
10444                          *
10445                          *   <push int/long ptr>
10446                          *   <push int/long>
10447                          *   box MyFlags
10448                          *   constrained. MyFlags
10449                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10450                          *
10451                          * If we find this sequence and the operand types on box and constrained
10452                          * are equal, we can emit a specialized instruction sequence instead of
10453                          * the very slow HasFlag () call.
10454                          */
10455                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10456                             /* Cheap checks first. */
10457                             ip + 5 + 6 + 5 < end &&
10458                             ip [5] == CEE_PREFIX1 &&
10459                             ip [6] == CEE_CONSTRAINED_ &&
10460                             ip [11] == CEE_CALLVIRT &&
10461                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10462                             mono_class_is_enum (klass) &&
10463                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10464                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10465                             has_flag->klass == mono_defaults.enum_class &&
10466                             !strcmp (has_flag->name, "HasFlag") &&
10467                             has_flag->signature->hasthis &&
10468                             has_flag->signature->param_count == 1) {
10469                                 CHECK_TYPELOAD (enum_class);
10470
10471                                 if (enum_class == klass) {
10472                                         MonoInst *enum_this, *enum_flag;
10473
10474                                         ip += 5 + 6 + 5;
10475                                         --sp;
10476
10477                                         enum_this = sp [0];
10478                                         enum_flag = sp [1];
10479
10480                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10481                                         break;
10482                                 }
10483                         }
10484
10485                         // FIXME: LLVM can't handle the inconsistent bb linking
10486                         if (!mono_class_is_nullable (klass) &&
10487                                 !mini_is_gsharedvt_klass (klass) &&
10488                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10489                                 (ip [5] == CEE_BRTRUE || 
10490                                  ip [5] == CEE_BRTRUE_S ||
10491                                  ip [5] == CEE_BRFALSE ||
10492                                  ip [5] == CEE_BRFALSE_S)) {
10493                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10494                                 int dreg;
10495                                 MonoBasicBlock *true_bb, *false_bb;
10496
10497                                 ip += 5;
10498
10499                                 if (cfg->verbose_level > 3) {
10500                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10501                                         printf ("<box+brtrue opt>\n");
10502                                 }
10503
10504                                 switch (*ip) {
10505                                 case CEE_BRTRUE_S:
10506                                 case CEE_BRFALSE_S:
10507                                         CHECK_OPSIZE (2);
10508                                         ip++;
10509                                         target = ip + 1 + (signed char)(*ip);
10510                                         ip++;
10511                                         break;
10512                                 case CEE_BRTRUE:
10513                                 case CEE_BRFALSE:
10514                                         CHECK_OPSIZE (5);
10515                                         ip++;
10516                                         target = ip + 4 + (gint)(read32 (ip));
10517                                         ip += 4;
10518                                         break;
10519                                 default:
10520                                         g_assert_not_reached ();
10521                                 }
10522
10523                                 /* 
10524                                  * We need to link both bblocks, since it is needed for handling stack
10525                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10526                                  * Branching to only one of them would lead to inconsistencies, so
10527                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10528                                  */
10529                                 GET_BBLOCK (cfg, true_bb, target);
10530                                 GET_BBLOCK (cfg, false_bb, ip);
10531
10532                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10533                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10534
10535                                 if (sp != stack_start) {
10536                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10537                                         sp = stack_start;
10538                                         CHECK_UNVERIFIABLE (cfg);
10539                                 }
10540
10541                                 if (COMPILE_LLVM (cfg)) {
10542                                         dreg = alloc_ireg (cfg);
10543                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10544                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10545
10546                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10547                                 } else {
10548                                         /* The JIT can't eliminate the iconst+compare */
10549                                         MONO_INST_NEW (cfg, ins, OP_BR);
10550                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10551                                         MONO_ADD_INS (cfg->cbb, ins);
10552                                 }
10553
10554                                 start_new_bblock = 1;
10555                                 break;
10556                         }
10557
10558                         *sp++ = handle_box (cfg, val, klass, context_used);
10559
10560                         CHECK_CFG_EXCEPTION;
10561                         ip += 5;
10562                         inline_costs += 1;
10563                         break;
10564                 }
10565                 case CEE_UNBOX: {
10566                         CHECK_STACK (1);
10567                         --sp;
10568                         CHECK_OPSIZE (5);
10569                         token = read32 (ip + 1);
10570                         klass = mini_get_class (method, token, generic_context);
10571                         CHECK_TYPELOAD (klass);
10572
10573                         mono_save_token_info (cfg, image, token, klass);
10574
10575                         context_used = mini_class_check_context_used (cfg, klass);
10576
10577                         if (mono_class_is_nullable (klass)) {
10578                                 MonoInst *val;
10579
10580                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10581                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10582
10583                                 *sp++= ins;
10584                         } else {
10585                                 ins = handle_unbox (cfg, klass, sp, context_used);
10586                                 *sp++ = ins;
10587                         }
10588                         ip += 5;
10589                         inline_costs += 2;
10590                         break;
10591                 }
10592                 case CEE_LDFLD:
10593                 case CEE_LDFLDA:
10594                 case CEE_STFLD:
10595                 case CEE_LDSFLD:
10596                 case CEE_LDSFLDA:
10597                 case CEE_STSFLD: {
10598                         MonoClassField *field;
10599 #ifndef DISABLE_REMOTING
10600                         int costs;
10601 #endif
10602                         guint foffset;
10603                         gboolean is_instance;
10604                         int op;
10605                         gpointer addr = NULL;
10606                         gboolean is_special_static;
10607                         MonoType *ftype;
10608                         MonoInst *store_val = NULL;
10609                         MonoInst *thread_ins;
10610
10611                         op = *ip;
10612                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10613                         if (is_instance) {
10614                                 if (op == CEE_STFLD) {
10615                                         CHECK_STACK (2);
10616                                         sp -= 2;
10617                                         store_val = sp [1];
10618                                 } else {
10619                                         CHECK_STACK (1);
10620                                         --sp;
10621                                 }
10622                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10623                                         UNVERIFIED;
10624                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10625                                         UNVERIFIED;
10626                         } else {
10627                                 if (op == CEE_STSFLD) {
10628                                         CHECK_STACK (1);
10629                                         sp--;
10630                                         store_val = sp [0];
10631                                 }
10632                         }
10633
10634                         CHECK_OPSIZE (5);
10635                         token = read32 (ip + 1);
10636                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10637                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
10638                                 klass = field->parent;
10639                         }
10640                         else {
10641                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10642                                 CHECK_CFG_ERROR;
10643                         }
10644                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10645                                 FIELD_ACCESS_FAILURE (method, field);
10646                         mono_class_init (klass);
10647
10648                         /* if the class is Critical then transparent code cannot access it's fields */
10649                         if (!is_instance && mono_security_core_clr_enabled ())
10650                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10651
10652                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10653                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10654                         if (mono_security_core_clr_enabled ())
10655                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10656                         */
10657
10658                         ftype = mono_field_get_type (field);
10659
10660                         /*
10661                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10662                          * the static case.
10663                          */
10664                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
10665                                 switch (op) {
10666                                 case CEE_LDFLD:
10667                                         op = CEE_LDSFLD;
10668                                         break;
10669                                 case CEE_STFLD:
10670                                         op = CEE_STSFLD;
10671                                         break;
10672                                 case CEE_LDFLDA:
10673                                         op = CEE_LDSFLDA;
10674                                         break;
10675                                 default:
10676                                         g_assert_not_reached ();
10677                                 }
10678                                 is_instance = FALSE;
10679                         }
10680
10681                         context_used = mini_class_check_context_used (cfg, klass);
10682
10683                         /* INSTANCE CASE */
10684
10685                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10686                         if (op == CEE_STFLD) {
10687                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10688                                         UNVERIFIED;
10689 #ifndef DISABLE_REMOTING
10690                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10691                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10692                                         MonoInst *iargs [5];
10693
10694                                         GSHAREDVT_FAILURE (op);
10695
10696                                         iargs [0] = sp [0];
10697                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10698                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10699                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10700                                                     field->offset);
10701                                         iargs [4] = sp [1];
10702
10703                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10704                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10705                                                                                            iargs, ip, cfg->real_offset, TRUE);
10706                                                 CHECK_CFG_EXCEPTION;
10707                                                 g_assert (costs > 0);
10708                                                       
10709                                                 cfg->real_offset += 5;
10710
10711                                                 inline_costs += costs;
10712                                         } else {
10713                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10714                                         }
10715                                 } else
10716 #endif
10717                                 {
10718                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
10719
10720                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10721
10722                                         if (ins_flag & MONO_INST_VOLATILE) {
10723                                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10724                                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10725                                         }
10726
10727                                         if (mini_is_gsharedvt_klass (klass)) {
10728                                                 MonoInst *offset_ins;
10729
10730                                                 context_used = mini_class_check_context_used (cfg, klass);
10731
10732                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10733                                                 /* The value is offset by 1 */
10734                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10735                                                 dreg = alloc_ireg_mp (cfg);
10736                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10737                                                 wbarrier_ptr_ins = ins;
10738                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10739                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10740                                         } else {
10741                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10742                                         }
10743                                         if (sp [0]->opcode != OP_LDADDR)
10744                                                 store->flags |= MONO_INST_FAULT;
10745
10746                                         if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
10747                                                 if (mini_is_gsharedvt_klass (klass)) {
10748                                                         g_assert (wbarrier_ptr_ins);
10749                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
10750                                                 } else {
10751                                                         /* insert call to write barrier */
10752                                                         MonoInst *ptr;
10753                                                         int dreg;
10754
10755                                                         dreg = alloc_ireg_mp (cfg);
10756                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10757                                                         emit_write_barrier (cfg, ptr, sp [1]);
10758                                                 }
10759                                         }
10760
10761                                         store->flags |= ins_flag;
10762                                 }
10763                                 ins_flag = 0;
10764                                 ip += 5;
10765                                 break;
10766                         }
10767
10768 #ifndef DISABLE_REMOTING
10769                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10770                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10771                                 MonoInst *iargs [4];
10772
10773                                 GSHAREDVT_FAILURE (op);
10774
10775                                 iargs [0] = sp [0];
10776                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10777                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10778                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10779                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10780                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10781                                                                                    iargs, ip, cfg->real_offset, TRUE);
10782                                         CHECK_CFG_EXCEPTION;
10783                                         g_assert (costs > 0);
10784                                                       
10785                                         cfg->real_offset += 5;
10786
10787                                         *sp++ = iargs [0];
10788
10789                                         inline_costs += costs;
10790                                 } else {
10791                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10792                                         *sp++ = ins;
10793                                 }
10794                         } else 
10795 #endif
10796                         if (is_instance) {
10797                                 if (sp [0]->type == STACK_VTYPE) {
10798                                         MonoInst *var;
10799
10800                                         /* Have to compute the address of the variable */
10801
10802                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10803                                         if (!var)
10804                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10805                                         else
10806                                                 g_assert (var->klass == klass);
10807                                         
10808                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10809                                         sp [0] = ins;
10810                                 }
10811
10812                                 if (op == CEE_LDFLDA) {
10813                                         if (sp [0]->type == STACK_OBJ) {
10814                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10815                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10816                                         }
10817
10818                                         dreg = alloc_ireg_mp (cfg);
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                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10827                                         } else {
10828                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10829                                         }
10830                                         ins->klass = mono_class_from_mono_type (field->type);
10831                                         ins->type = STACK_MP;
10832                                         *sp++ = ins;
10833                                 } else {
10834                                         MonoInst *load;
10835
10836                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10837
10838                                         if (sp [0]->opcode == OP_LDADDR && klass->simd_type && cfg->opt & MONO_OPT_SIMD) {
10839                                                 ins = mono_emit_simd_field_load (cfg, field, sp [0]);
10840                                                 if (ins) {
10841                                                         *sp++ = ins;
10842                                                         ins_flag = 0;
10843                                                         ip += 5;
10844                                                         break;
10845                                                 }
10846                                         }
10847
10848                                         if (mini_is_gsharedvt_klass (klass)) {
10849                                                 MonoInst *offset_ins;
10850
10851                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10852                                                 /* The value is offset by 1 */
10853                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10854                                                 dreg = alloc_ireg_mp (cfg);
10855                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10856                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10857                                         } else {
10858                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10859                                         }
10860                                         load->flags |= ins_flag;
10861                                         if (sp [0]->opcode != OP_LDADDR)
10862                                                 load->flags |= MONO_INST_FAULT;
10863                                         *sp++ = load;
10864                                 }
10865                         }
10866
10867                         if (is_instance) {
10868                                 ins_flag = 0;
10869                                 ip += 5;
10870                                 break;
10871                         }
10872
10873                         /* STATIC CASE */
10874                         context_used = mini_class_check_context_used (cfg, klass);
10875
10876                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
10877                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
10878                                 CHECK_CFG_ERROR;
10879                         }
10880
10881                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10882                          * to be called here.
10883                          */
10884                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10885                                 mono_class_vtable (cfg->domain, klass);
10886                                 CHECK_TYPELOAD (klass);
10887                         }
10888                         mono_domain_lock (cfg->domain);
10889                         if (cfg->domain->special_static_fields)
10890                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10891                         mono_domain_unlock (cfg->domain);
10892
10893                         is_special_static = mono_class_field_is_special_static (field);
10894
10895                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10896                                 thread_ins = mono_create_tls_get (cfg, TLS_KEY_THREAD);
10897                         else
10898                                 thread_ins = NULL;
10899
10900                         /* Generate IR to compute the field address */
10901                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10902                                 /*
10903                                  * Fast access to TLS data
10904                                  * Inline version of get_thread_static_data () in
10905                                  * threads.c.
10906                                  */
10907                                 guint32 offset;
10908                                 int idx, static_data_reg, array_reg, dreg;
10909
10910                                 if (context_used && cfg->gsharedvt && mini_is_gsharedvt_klass (klass))
10911                                         GSHAREDVT_FAILURE (op);
10912
10913                                 static_data_reg = alloc_ireg (cfg);
10914                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
10915
10916                                 if (cfg->compile_aot) {
10917                                         int offset_reg, offset2_reg, idx_reg;
10918
10919                                         /* For TLS variables, this will return the TLS offset */
10920                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10921                                         offset_reg = ins->dreg;
10922                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10923                                         idx_reg = alloc_ireg (cfg);
10924                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
10925                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10926                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10927                                         array_reg = alloc_ireg (cfg);
10928                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10929                                         offset2_reg = alloc_ireg (cfg);
10930                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
10931                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
10932                                         dreg = alloc_ireg (cfg);
10933                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10934                                 } else {
10935                                         offset = (gsize)addr & 0x7fffffff;
10936                                         idx = offset & 0x3f;
10937
10938                                         array_reg = alloc_ireg (cfg);
10939                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10940                                         dreg = alloc_ireg (cfg);
10941                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
10942                                 }
10943                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10944                                         (cfg->compile_aot && is_special_static) ||
10945                                         (context_used && is_special_static)) {
10946                                 MonoInst *iargs [2];
10947
10948                                 g_assert (field->parent);
10949                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10950                                 if (context_used) {
10951                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10952                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10953                                 } else {
10954                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10955                                 }
10956                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10957                         } else if (context_used) {
10958                                 MonoInst *static_data;
10959
10960                                 /*
10961                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10962                                         method->klass->name_space, method->klass->name, method->name,
10963                                         depth, field->offset);
10964                                 */
10965
10966                                 if (mono_class_needs_cctor_run (klass, method))
10967                                         emit_class_init (cfg, klass);
10968
10969                                 /*
10970                                  * The pointer we're computing here is
10971                                  *
10972                                  *   super_info.static_data + field->offset
10973                                  */
10974                                 static_data = mini_emit_get_rgctx_klass (cfg, context_used,
10975                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10976
10977                                 if (mini_is_gsharedvt_klass (klass)) {
10978                                         MonoInst *offset_ins;
10979
10980                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10981                                         /* The value is offset by 1 */
10982                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10983                                         dreg = alloc_ireg_mp (cfg);
10984                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10985                                 } else if (field->offset == 0) {
10986                                         ins = static_data;
10987                                 } else {
10988                                         int addr_reg = mono_alloc_preg (cfg);
10989                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10990                                 }
10991                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10992                                 MonoInst *iargs [2];
10993
10994                                 g_assert (field->parent);
10995                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10996                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10997                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10998                         } else {
10999                                 MonoVTable *vtable = NULL;
11000
11001                                 if (!cfg->compile_aot)
11002                                         vtable = mono_class_vtable (cfg->domain, klass);
11003                                 CHECK_TYPELOAD (klass);
11004
11005                                 if (!addr) {
11006                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11007                                                 if (!(g_slist_find (class_inits, klass))) {
11008                                                         emit_class_init (cfg, klass);
11009                                                         if (cfg->verbose_level > 2)
11010                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11011                                                         class_inits = g_slist_prepend (class_inits, klass);
11012                                                 }
11013                                         } else {
11014                                                 if (cfg->run_cctors) {
11015                                                         /* This makes so that inline cannot trigger */
11016                                                         /* .cctors: too many apps depend on them */
11017                                                         /* running with a specific order... */
11018                                                         g_assert (vtable);
11019                                                         if (! vtable->initialized)
11020                                                                 INLINE_FAILURE ("class init");
11021                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
11022                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11023                                                                 goto exception_exit;
11024                                                         }
11025                                                 }
11026                                         }
11027                                         if (cfg->compile_aot)
11028                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11029                                         else {
11030                                                 g_assert (vtable);
11031                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11032                                                 g_assert (addr);
11033                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11034                                         }
11035                                 } else {
11036                                         MonoInst *iargs [1];
11037                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11038                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11039                                 }
11040                         }
11041
11042                         /* Generate IR to do the actual load/store operation */
11043
11044                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11045                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11046                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11047                         }
11048
11049                         if (op == CEE_LDSFLDA) {
11050                                 ins->klass = mono_class_from_mono_type (ftype);
11051                                 ins->type = STACK_PTR;
11052                                 *sp++ = ins;
11053                         } else if (op == CEE_STSFLD) {
11054                                 MonoInst *store;
11055
11056                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11057                                 store->flags |= ins_flag;
11058                         } else {
11059                                 gboolean is_const = FALSE;
11060                                 MonoVTable *vtable = NULL;
11061                                 gpointer addr = NULL;
11062
11063                                 if (!context_used) {
11064                                         vtable = mono_class_vtable (cfg->domain, klass);
11065                                         CHECK_TYPELOAD (klass);
11066                                 }
11067                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11068                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11069                                         int ro_type = ftype->type;
11070                                         if (!addr)
11071                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11072                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11073                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11074                                         }
11075
11076                                         GSHAREDVT_FAILURE (op);
11077
11078                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11079                                         is_const = TRUE;
11080                                         switch (ro_type) {
11081                                         case MONO_TYPE_BOOLEAN:
11082                                         case MONO_TYPE_U1:
11083                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11084                                                 sp++;
11085                                                 break;
11086                                         case MONO_TYPE_I1:
11087                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11088                                                 sp++;
11089                                                 break;                                          
11090                                         case MONO_TYPE_CHAR:
11091                                         case MONO_TYPE_U2:
11092                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11093                                                 sp++;
11094                                                 break;
11095                                         case MONO_TYPE_I2:
11096                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11097                                                 sp++;
11098                                                 break;
11099                                                 break;
11100                                         case MONO_TYPE_I4:
11101                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11102                                                 sp++;
11103                                                 break;                                          
11104                                         case MONO_TYPE_U4:
11105                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11106                                                 sp++;
11107                                                 break;
11108                                         case MONO_TYPE_I:
11109                                         case MONO_TYPE_U:
11110                                         case MONO_TYPE_PTR:
11111                                         case MONO_TYPE_FNPTR:
11112                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11113                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11114                                                 sp++;
11115                                                 break;
11116                                         case MONO_TYPE_STRING:
11117                                         case MONO_TYPE_OBJECT:
11118                                         case MONO_TYPE_CLASS:
11119                                         case MONO_TYPE_SZARRAY:
11120                                         case MONO_TYPE_ARRAY:
11121                                                 if (!mono_gc_is_moving ()) {
11122                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11123                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11124                                                         sp++;
11125                                                 } else {
11126                                                         is_const = FALSE;
11127                                                 }
11128                                                 break;
11129                                         case MONO_TYPE_I8:
11130                                         case MONO_TYPE_U8:
11131                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11132                                                 sp++;
11133                                                 break;
11134                                         case MONO_TYPE_R4:
11135                                         case MONO_TYPE_R8:
11136                                         case MONO_TYPE_VALUETYPE:
11137                                         default:
11138                                                 is_const = FALSE;
11139                                                 break;
11140                                         }
11141                                 }
11142
11143                                 if (!is_const) {
11144                                         MonoInst *load;
11145
11146                                         CHECK_STACK_OVF (1);
11147
11148                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11149                                         load->flags |= ins_flag;
11150                                         ins_flag = 0;
11151                                         *sp++ = load;
11152                                 }
11153                         }
11154
11155                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11156                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11157                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11158                         }
11159
11160                         ins_flag = 0;
11161                         ip += 5;
11162                         break;
11163                 }
11164                 case CEE_STOBJ:
11165                         CHECK_STACK (2);
11166                         sp -= 2;
11167                         CHECK_OPSIZE (5);
11168                         token = read32 (ip + 1);
11169                         klass = mini_get_class (method, token, generic_context);
11170                         CHECK_TYPELOAD (klass);
11171                         if (ins_flag & MONO_INST_VOLATILE) {
11172                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11173                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11174                         }
11175                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11176                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11177                         ins->flags |= ins_flag;
11178                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11179                                 generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
11180                                 /* insert call to write barrier */
11181                                 emit_write_barrier (cfg, sp [0], sp [1]);
11182                         }
11183                         ins_flag = 0;
11184                         ip += 5;
11185                         inline_costs += 1;
11186                         break;
11187
11188                         /*
11189                          * Array opcodes
11190                          */
11191                 case CEE_NEWARR: {
11192                         MonoInst *len_ins;
11193                         const char *data_ptr;
11194                         int data_size = 0;
11195                         guint32 field_token;
11196
11197                         CHECK_STACK (1);
11198                         --sp;
11199
11200                         CHECK_OPSIZE (5);
11201                         token = read32 (ip + 1);
11202
11203                         klass = mini_get_class (method, token, generic_context);
11204                         CHECK_TYPELOAD (klass);
11205
11206                         context_used = mini_class_check_context_used (cfg, klass);
11207
11208                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11209                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11210                                 ins->sreg1 = sp [0]->dreg;
11211                                 ins->type = STACK_I4;
11212                                 ins->dreg = alloc_ireg (cfg);
11213                                 MONO_ADD_INS (cfg->cbb, ins);
11214                                 *sp = mono_decompose_opcode (cfg, ins);
11215                         }
11216
11217                         if (context_used) {
11218                                 MonoInst *args [3];
11219                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11220                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11221
11222                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11223
11224                                 /* vtable */
11225                                 args [0] = mini_emit_get_rgctx_klass (cfg, context_used,
11226                                         array_class, MONO_RGCTX_INFO_VTABLE);
11227                                 /* array len */
11228                                 args [1] = sp [0];
11229
11230                                 if (managed_alloc)
11231                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11232                                 else
11233                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11234                         } else {
11235                                 if (cfg->opt & MONO_OPT_SHARED) {
11236                                         /* Decompose now to avoid problems with references to the domainvar */
11237                                         MonoInst *iargs [3];
11238
11239                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11240                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11241                                         iargs [2] = sp [0];
11242
11243                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11244                                 } else {
11245                                         /* Decompose later since it is needed by abcrem */
11246                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11247                                         mono_class_vtable (cfg->domain, array_type);
11248                                         CHECK_TYPELOAD (array_type);
11249
11250                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11251                                         ins->dreg = alloc_ireg_ref (cfg);
11252                                         ins->sreg1 = sp [0]->dreg;
11253                                         ins->inst_newa_class = klass;
11254                                         ins->type = STACK_OBJ;
11255                                         ins->klass = array_type;
11256                                         MONO_ADD_INS (cfg->cbb, ins);
11257                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11258                                         cfg->cbb->has_array_access = TRUE;
11259
11260                                         /* Needed so mono_emit_load_get_addr () gets called */
11261                                         mono_get_got_var (cfg);
11262                                 }
11263                         }
11264
11265                         len_ins = sp [0];
11266                         ip += 5;
11267                         *sp++ = ins;
11268                         inline_costs += 1;
11269
11270                         /* 
11271                          * we inline/optimize the initialization sequence if possible.
11272                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11273                          * for small sizes open code the memcpy
11274                          * ensure the rva field is big enough
11275                          */
11276                         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))) {
11277                                 MonoMethod *memcpy_method = get_memcpy_method ();
11278                                 MonoInst *iargs [3];
11279                                 int add_reg = alloc_ireg_mp (cfg);
11280
11281                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11282                                 if (cfg->compile_aot) {
11283                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11284                                 } else {
11285                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11286                                 }
11287                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11288                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11289                                 ip += 11;
11290                         }
11291
11292                         break;
11293                 }
11294                 case CEE_LDLEN:
11295                         CHECK_STACK (1);
11296                         --sp;
11297                         if (sp [0]->type != STACK_OBJ)
11298                                 UNVERIFIED;
11299
11300                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11301                         ins->dreg = alloc_preg (cfg);
11302                         ins->sreg1 = sp [0]->dreg;
11303                         ins->type = STACK_I4;
11304                         /* This flag will be inherited by the decomposition */
11305                         ins->flags |= MONO_INST_FAULT;
11306                         MONO_ADD_INS (cfg->cbb, ins);
11307                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11308                         cfg->cbb->has_array_access = TRUE;
11309                         ip ++;
11310                         *sp++ = ins;
11311                         break;
11312                 case CEE_LDELEMA:
11313                         CHECK_STACK (2);
11314                         sp -= 2;
11315                         CHECK_OPSIZE (5);
11316                         if (sp [0]->type != STACK_OBJ)
11317                                 UNVERIFIED;
11318
11319                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11320
11321                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11322                         CHECK_TYPELOAD (klass);
11323                         /* we need to make sure that this array is exactly the type it needs
11324                          * to be for correctness. the wrappers are lax with their usage
11325                          * so we need to ignore them here
11326                          */
11327                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11328                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11329                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11330                                 CHECK_TYPELOAD (array_class);
11331                         }
11332
11333                         readonly = FALSE;
11334                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11335                         *sp++ = ins;
11336                         ip += 5;
11337                         break;
11338                 case CEE_LDELEM:
11339                 case CEE_LDELEM_I1:
11340                 case CEE_LDELEM_U1:
11341                 case CEE_LDELEM_I2:
11342                 case CEE_LDELEM_U2:
11343                 case CEE_LDELEM_I4:
11344                 case CEE_LDELEM_U4:
11345                 case CEE_LDELEM_I8:
11346                 case CEE_LDELEM_I:
11347                 case CEE_LDELEM_R4:
11348                 case CEE_LDELEM_R8:
11349                 case CEE_LDELEM_REF: {
11350                         MonoInst *addr;
11351
11352                         CHECK_STACK (2);
11353                         sp -= 2;
11354
11355                         if (*ip == CEE_LDELEM) {
11356                                 CHECK_OPSIZE (5);
11357                                 token = read32 (ip + 1);
11358                                 klass = mini_get_class (method, token, generic_context);
11359                                 CHECK_TYPELOAD (klass);
11360                                 mono_class_init (klass);
11361                         }
11362                         else
11363                                 klass = array_access_to_klass (*ip);
11364
11365                         if (sp [0]->type != STACK_OBJ)
11366                                 UNVERIFIED;
11367
11368                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11369
11370                         if (mini_is_gsharedvt_variable_klass (klass)) {
11371                                 // FIXME-VT: OP_ICONST optimization
11372                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11373                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11374                                 ins->opcode = OP_LOADV_MEMBASE;
11375                         } else if (sp [1]->opcode == OP_ICONST) {
11376                                 int array_reg = sp [0]->dreg;
11377                                 int index_reg = sp [1]->dreg;
11378                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11379
11380                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
11381                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
11382
11383                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11384                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11385                         } else {
11386                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11387                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11388                         }
11389                         *sp++ = ins;
11390                         if (*ip == CEE_LDELEM)
11391                                 ip += 5;
11392                         else
11393                                 ++ip;
11394                         break;
11395                 }
11396                 case CEE_STELEM_I:
11397                 case CEE_STELEM_I1:
11398                 case CEE_STELEM_I2:
11399                 case CEE_STELEM_I4:
11400                 case CEE_STELEM_I8:
11401                 case CEE_STELEM_R4:
11402                 case CEE_STELEM_R8:
11403                 case CEE_STELEM_REF:
11404                 case CEE_STELEM: {
11405                         CHECK_STACK (3);
11406                         sp -= 3;
11407
11408                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11409
11410                         if (*ip == CEE_STELEM) {
11411                                 CHECK_OPSIZE (5);
11412                                 token = read32 (ip + 1);
11413                                 klass = mini_get_class (method, token, generic_context);
11414                                 CHECK_TYPELOAD (klass);
11415                                 mono_class_init (klass);
11416                         }
11417                         else
11418                                 klass = array_access_to_klass (*ip);
11419
11420                         if (sp [0]->type != STACK_OBJ)
11421                                 UNVERIFIED;
11422
11423                         emit_array_store (cfg, klass, sp, TRUE);
11424
11425                         if (*ip == CEE_STELEM)
11426                                 ip += 5;
11427                         else
11428                                 ++ip;
11429                         inline_costs += 1;
11430                         break;
11431                 }
11432                 case CEE_CKFINITE: {
11433                         CHECK_STACK (1);
11434                         --sp;
11435
11436                         if (cfg->llvm_only) {
11437                                 MonoInst *iargs [1];
11438
11439                                 iargs [0] = sp [0];
11440                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11441                         } else  {
11442                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11443                                 ins->sreg1 = sp [0]->dreg;
11444                                 ins->dreg = alloc_freg (cfg);
11445                                 ins->type = STACK_R8;
11446                                 MONO_ADD_INS (cfg->cbb, ins);
11447
11448                                 *sp++ = mono_decompose_opcode (cfg, ins);
11449                         }
11450
11451                         ++ip;
11452                         break;
11453                 }
11454                 case CEE_REFANYVAL: {
11455                         MonoInst *src_var, *src;
11456
11457                         int klass_reg = alloc_preg (cfg);
11458                         int dreg = alloc_preg (cfg);
11459
11460                         GSHAREDVT_FAILURE (*ip);
11461
11462                         CHECK_STACK (1);
11463                         MONO_INST_NEW (cfg, ins, *ip);
11464                         --sp;
11465                         CHECK_OPSIZE (5);
11466                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11467                         CHECK_TYPELOAD (klass);
11468
11469                         context_used = mini_class_check_context_used (cfg, klass);
11470
11471                         // FIXME:
11472                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11473                         if (!src_var)
11474                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11475                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11476                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11477
11478                         if (context_used) {
11479                                 MonoInst *klass_ins;
11480
11481                                 klass_ins = mini_emit_get_rgctx_klass (cfg, context_used,
11482                                                 klass, MONO_RGCTX_INFO_KLASS);
11483
11484                                 // FIXME:
11485                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11486                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11487                         } else {
11488                                 mini_emit_class_check (cfg, klass_reg, klass);
11489                         }
11490                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11491                         ins->type = STACK_MP;
11492                         ins->klass = klass;
11493                         *sp++ = ins;
11494                         ip += 5;
11495                         break;
11496                 }
11497                 case CEE_MKREFANY: {
11498                         MonoInst *loc, *addr;
11499
11500                         GSHAREDVT_FAILURE (*ip);
11501
11502                         CHECK_STACK (1);
11503                         MONO_INST_NEW (cfg, ins, *ip);
11504                         --sp;
11505                         CHECK_OPSIZE (5);
11506                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11507                         CHECK_TYPELOAD (klass);
11508
11509                         context_used = mini_class_check_context_used (cfg, klass);
11510
11511                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11512                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11513
11514                         if (context_used) {
11515                                 MonoInst *const_ins;
11516                                 int type_reg = alloc_preg (cfg);
11517
11518                                 const_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11519                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11520                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11521                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11522                         } else {
11523                                 int const_reg = alloc_preg (cfg);
11524                                 int type_reg = alloc_preg (cfg);
11525
11526                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11527                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11528                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11529                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11530                         }
11531                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11532
11533                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11534                         ins->type = STACK_VTYPE;
11535                         ins->klass = mono_defaults.typed_reference_class;
11536                         *sp++ = ins;
11537                         ip += 5;
11538                         break;
11539                 }
11540                 case CEE_LDTOKEN: {
11541                         gpointer handle;
11542                         MonoClass *handle_class;
11543
11544                         CHECK_STACK_OVF (1);
11545
11546                         CHECK_OPSIZE (5);
11547                         n = read32 (ip + 1);
11548
11549                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11550                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11551                                 handle = mono_method_get_wrapper_data (method, n);
11552                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
11553                                 if (handle_class == mono_defaults.typehandle_class)
11554                                         handle = &((MonoClass*)handle)->byval_arg;
11555                         }
11556                         else {
11557                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11558                                 CHECK_CFG_ERROR;
11559                         }
11560                         if (!handle)
11561                                 LOAD_ERROR;
11562                         mono_class_init (handle_class);
11563                         if (cfg->gshared) {
11564                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11565                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11566                                         /* This case handles ldtoken
11567                                            of an open type, like for
11568                                            typeof(Gen<>). */
11569                                         context_used = 0;
11570                                 } else if (handle_class == mono_defaults.typehandle_class) {
11571                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
11572                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11573                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11574                                 else if (handle_class == mono_defaults.methodhandle_class)
11575                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
11576                                 else
11577                                         g_assert_not_reached ();
11578                         }
11579
11580                         if ((cfg->opt & MONO_OPT_SHARED) &&
11581                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11582                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11583                                 MonoInst *addr, *vtvar, *iargs [3];
11584                                 int method_context_used;
11585
11586                                 method_context_used = mini_method_check_context_used (cfg, method);
11587
11588                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11589
11590                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11591                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11592                                 if (method_context_used) {
11593                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11594                                                 method, MONO_RGCTX_INFO_METHOD);
11595                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11596                                 } else {
11597                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11598                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11599                                 }
11600                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11601
11602                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11603
11604                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11605                         } else {
11606                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11607                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11608                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11609                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11610                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11611                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
11612
11613                                         mono_class_init (tclass);
11614                                         if (context_used) {
11615                                                 ins = mini_emit_get_rgctx_klass (cfg, context_used,
11616                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11617                                         } else if (cfg->compile_aot) {
11618                                                 if (method->wrapper_type) {
11619                                                         error_init (&error); //got to do it since there are multiple conditionals below
11620                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11621                                                                 /* Special case for static synchronized wrappers */
11622                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11623                                                         } else {
11624                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11625                                                                 /* FIXME: n is not a normal token */
11626                                                                 DISABLE_AOT (cfg);
11627                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11628                                                         }
11629                                                 } else {
11630                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11631                                                 }
11632                                         } else {
11633                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
11634                                                 CHECK_CFG_ERROR;
11635                                                 EMIT_NEW_PCONST (cfg, ins, rt);
11636                                         }
11637                                         ins->type = STACK_OBJ;
11638                                         ins->klass = cmethod->klass;
11639                                         ip += 5;
11640                                 } else {
11641                                         MonoInst *addr, *vtvar;
11642
11643                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11644
11645                                         if (context_used) {
11646                                                 if (handle_class == mono_defaults.typehandle_class) {
11647                                                         ins = mini_emit_get_rgctx_klass (cfg, context_used,
11648                                                                         mono_class_from_mono_type ((MonoType *)handle),
11649                                                                         MONO_RGCTX_INFO_TYPE);
11650                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11651                                                         ins = emit_get_rgctx_method (cfg, context_used,
11652                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
11653                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11654                                                         ins = emit_get_rgctx_field (cfg, context_used,
11655                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
11656                                                 } else {
11657                                                         g_assert_not_reached ();
11658                                                 }
11659                                         } else if (cfg->compile_aot) {
11660                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11661                                         } else {
11662                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11663                                         }
11664                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11665                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11666                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11667                                 }
11668                         }
11669
11670                         *sp++ = ins;
11671                         ip += 5;
11672                         break;
11673                 }
11674                 case CEE_THROW:
11675                         CHECK_STACK (1);
11676                         if (sp [-1]->type != STACK_OBJ)
11677                                 UNVERIFIED;
11678
11679                         MONO_INST_NEW (cfg, ins, OP_THROW);
11680                         --sp;
11681                         ins->sreg1 = sp [0]->dreg;
11682                         ip++;
11683                         cfg->cbb->out_of_line = TRUE;
11684                         MONO_ADD_INS (cfg->cbb, ins);
11685                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11686                         MONO_ADD_INS (cfg->cbb, ins);
11687                         sp = stack_start;
11688                         
11689                         link_bblock (cfg, cfg->cbb, end_bblock);
11690                         start_new_bblock = 1;
11691                         /* This can complicate code generation for llvm since the return value might not be defined */
11692                         if (COMPILE_LLVM (cfg))
11693                                 INLINE_FAILURE ("throw");
11694                         break;
11695                 case CEE_ENDFINALLY:
11696                         if (!ip_in_finally_clause (cfg, ip - header->code))
11697                                 UNVERIFIED;
11698                         /* mono_save_seq_point_info () depends on this */
11699                         if (sp != stack_start)
11700                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11701                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11702                         MONO_ADD_INS (cfg->cbb, ins);
11703                         ip++;
11704                         start_new_bblock = 1;
11705
11706                         /*
11707                          * Control will leave the method so empty the stack, otherwise
11708                          * the next basic block will start with a nonempty stack.
11709                          */
11710                         while (sp != stack_start) {
11711                                 sp--;
11712                         }
11713                         break;
11714                 case CEE_LEAVE:
11715                 case CEE_LEAVE_S: {
11716                         GList *handlers;
11717
11718                         if (*ip == CEE_LEAVE) {
11719                                 CHECK_OPSIZE (5);
11720                                 target = ip + 5 + (gint32)read32(ip + 1);
11721                         } else {
11722                                 CHECK_OPSIZE (2);
11723                                 target = ip + 2 + (signed char)(ip [1]);
11724                         }
11725
11726                         /* empty the stack */
11727                         while (sp != stack_start) {
11728                                 sp--;
11729                         }
11730
11731                         /* 
11732                          * If this leave statement is in a catch block, check for a
11733                          * pending exception, and rethrow it if necessary.
11734                          * We avoid doing this in runtime invoke wrappers, since those are called
11735                          * by native code which excepts the wrapper to catch all exceptions.
11736                          */
11737                         for (i = 0; i < header->num_clauses; ++i) {
11738                                 MonoExceptionClause *clause = &header->clauses [i];
11739
11740                                 /* 
11741                                  * Use <= in the final comparison to handle clauses with multiple
11742                                  * leave statements, like in bug #78024.
11743                                  * The ordering of the exception clauses guarantees that we find the
11744                                  * innermost clause.
11745                                  */
11746                                 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) {
11747                                         MonoInst *exc_ins;
11748                                         MonoBasicBlock *dont_throw;
11749
11750                                         /*
11751                                           MonoInst *load;
11752
11753                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11754                                         */
11755
11756                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11757
11758                                         NEW_BBLOCK (cfg, dont_throw);
11759
11760                                         /*
11761                                          * Currently, we always rethrow the abort exception, despite the 
11762                                          * fact that this is not correct. See thread6.cs for an example. 
11763                                          * But propagating the abort exception is more important than 
11764                                          * getting the sematics right.
11765                                          */
11766                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11767                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11768                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11769
11770                                         MONO_START_BB (cfg, dont_throw);
11771                                 }
11772                         }
11773
11774 #ifdef ENABLE_LLVM
11775                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
11776 #endif
11777
11778                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11779                                 GList *tmp;
11780                                 MonoExceptionClause *clause;
11781
11782                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11783                                         clause = (MonoExceptionClause *)tmp->data;
11784                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11785                                         g_assert (tblock);
11786                                         link_bblock (cfg, cfg->cbb, tblock);
11787                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11788                                         ins->inst_target_bb = tblock;
11789                                         ins->inst_eh_block = clause;
11790                                         MONO_ADD_INS (cfg->cbb, ins);
11791                                         cfg->cbb->has_call_handler = 1;
11792                                         if (COMPILE_LLVM (cfg)) {
11793                                                 MonoBasicBlock *target_bb;
11794
11795                                                 /* 
11796                                                  * Link the finally bblock with the target, since it will
11797                                                  * conceptually branch there.
11798                                                  */
11799                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
11800                                                 GET_BBLOCK (cfg, target_bb, target);
11801                                                 link_bblock (cfg, tblock, target_bb);
11802                                         }
11803                                 }
11804                                 g_list_free (handlers);
11805                         } 
11806
11807                         MONO_INST_NEW (cfg, ins, OP_BR);
11808                         MONO_ADD_INS (cfg->cbb, ins);
11809                         GET_BBLOCK (cfg, tblock, target);
11810                         link_bblock (cfg, cfg->cbb, tblock);
11811                         ins->inst_target_bb = tblock;
11812
11813                         start_new_bblock = 1;
11814
11815                         if (*ip == CEE_LEAVE)
11816                                 ip += 5;
11817                         else
11818                                 ip += 2;
11819
11820                         break;
11821                 }
11822
11823                         /*
11824                          * Mono specific opcodes
11825                          */
11826                 case MONO_CUSTOM_PREFIX: {
11827
11828                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11829
11830                         CHECK_OPSIZE (2);
11831                         switch (ip [1]) {
11832                         case CEE_MONO_ICALL: {
11833                                 gpointer func;
11834                                 MonoJitICallInfo *info;
11835
11836                                 token = read32 (ip + 2);
11837                                 func = mono_method_get_wrapper_data (method, token);
11838                                 info = mono_find_jit_icall_by_addr (func);
11839                                 if (!info)
11840                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11841                                 g_assert (info);
11842
11843                                 CHECK_STACK (info->sig->param_count);
11844                                 sp -= info->sig->param_count;
11845
11846                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11847                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11848                                         *sp++ = ins;
11849
11850                                 ip += 6;
11851                                 inline_costs += 10 * num_calls++;
11852
11853                                 break;
11854                         }
11855                         case CEE_MONO_LDPTR_CARD_TABLE:
11856                         case CEE_MONO_LDPTR_NURSERY_START:
11857                         case CEE_MONO_LDPTR_NURSERY_BITS:
11858                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
11859                                 CHECK_STACK_OVF (1);
11860
11861                                 switch (ip [1]) {
11862                                         case CEE_MONO_LDPTR_CARD_TABLE:
11863                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
11864                                                 break;
11865                                         case CEE_MONO_LDPTR_NURSERY_START:
11866                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
11867                                                 break;
11868                                         case CEE_MONO_LDPTR_NURSERY_BITS:
11869                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
11870                                                 break;
11871                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
11872                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11873                                                 break;
11874                                 }
11875
11876                                 *sp++ = ins;
11877                                 ip += 2;
11878                                 inline_costs += 10 * num_calls++;
11879                                 break;
11880                         }
11881                         case CEE_MONO_LDPTR: {
11882                                 gpointer ptr;
11883
11884                                 CHECK_STACK_OVF (1);
11885                                 CHECK_OPSIZE (6);
11886                                 token = read32 (ip + 2);
11887
11888                                 ptr = mono_method_get_wrapper_data (method, token);
11889                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11890                                 *sp++ = ins;
11891                                 ip += 6;
11892                                 inline_costs += 10 * num_calls++;
11893                                 /* Can't embed random pointers into AOT code */
11894                                 DISABLE_AOT (cfg);
11895                                 break;
11896                         }
11897                         case CEE_MONO_JIT_ICALL_ADDR: {
11898                                 MonoJitICallInfo *callinfo;
11899                                 gpointer ptr;
11900
11901                                 CHECK_STACK_OVF (1);
11902                                 CHECK_OPSIZE (6);
11903                                 token = read32 (ip + 2);
11904
11905                                 ptr = mono_method_get_wrapper_data (method, token);
11906                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11907                                 g_assert (callinfo);
11908                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11909                                 *sp++ = ins;
11910                                 ip += 6;
11911                                 inline_costs += 10 * num_calls++;
11912                                 break;
11913                         }
11914                         case CEE_MONO_ICALL_ADDR: {
11915                                 MonoMethod *cmethod;
11916                                 gpointer ptr;
11917
11918                                 CHECK_STACK_OVF (1);
11919                                 CHECK_OPSIZE (6);
11920                                 token = read32 (ip + 2);
11921
11922                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
11923
11924                                 if (cfg->compile_aot) {
11925                                         if (cfg->direct_pinvoke && ip + 6 < end && (ip [6] == CEE_POP)) {
11926                                                 /*
11927                                                  * This is generated by emit_native_wrapper () to resolve the pinvoke address
11928                                                  * before the call, its not needed when using direct pinvoke.
11929                                                  * This is not an optimization, but its used to avoid looking up pinvokes
11930                                                  * on platforms which don't support dlopen ().
11931                                                  */
11932                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11933                                         } else {
11934                                                 EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11935                                         }
11936                                 } else {
11937                                         ptr = mono_lookup_internal_call (cmethod);
11938                                         g_assert (ptr);
11939                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11940                                 }
11941                                 *sp++ = ins;
11942                                 ip += 6;
11943                                 break;
11944                         }
11945                         case CEE_MONO_VTADDR: {
11946                                 MonoInst *src_var, *src;
11947
11948                                 CHECK_STACK (1);
11949                                 --sp;
11950
11951                                 // FIXME:
11952                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11953                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11954                                 *sp++ = src;
11955                                 ip += 2;
11956                                 break;
11957                         }
11958                         case CEE_MONO_NEWOBJ: {
11959                                 MonoInst *iargs [2];
11960
11961                                 CHECK_STACK_OVF (1);
11962                                 CHECK_OPSIZE (6);
11963                                 token = read32 (ip + 2);
11964                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11965                                 mono_class_init (klass);
11966                                 NEW_DOMAINCONST (cfg, iargs [0]);
11967                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11968                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11969                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11970                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
11971                                 ip += 6;
11972                                 inline_costs += 10 * num_calls++;
11973                                 break;
11974                         }
11975                         case CEE_MONO_OBJADDR:
11976                                 CHECK_STACK (1);
11977                                 --sp;
11978                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11979                                 ins->dreg = alloc_ireg_mp (cfg);
11980                                 ins->sreg1 = sp [0]->dreg;
11981                                 ins->type = STACK_MP;
11982                                 MONO_ADD_INS (cfg->cbb, ins);
11983                                 *sp++ = ins;
11984                                 ip += 2;
11985                                 break;
11986                         case CEE_MONO_LDNATIVEOBJ:
11987                                 /*
11988                                  * Similar to LDOBJ, but instead load the unmanaged 
11989                                  * representation of the vtype to the stack.
11990                                  */
11991                                 CHECK_STACK (1);
11992                                 CHECK_OPSIZE (6);
11993                                 --sp;
11994                                 token = read32 (ip + 2);
11995                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11996                                 g_assert (klass->valuetype);
11997                                 mono_class_init (klass);
11998
11999                                 {
12000                                         MonoInst *src, *dest, *temp;
12001
12002                                         src = sp [0];
12003                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12004                                         temp->backend.is_pinvoke = 1;
12005                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12006                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12007
12008                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12009                                         dest->type = STACK_VTYPE;
12010                                         dest->klass = klass;
12011
12012                                         *sp ++ = dest;
12013                                         ip += 6;
12014                                 }
12015                                 break;
12016                         case CEE_MONO_RETOBJ: {
12017                                 /*
12018                                  * Same as RET, but return the native representation of a vtype
12019                                  * to the caller.
12020                                  */
12021                                 g_assert (cfg->ret);
12022                                 g_assert (mono_method_signature (method)->pinvoke); 
12023                                 CHECK_STACK (1);
12024                                 --sp;
12025                                 
12026                                 CHECK_OPSIZE (6);
12027                                 token = read32 (ip + 2);    
12028                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12029
12030                                 if (!cfg->vret_addr) {
12031                                         g_assert (cfg->ret_var_is_local);
12032
12033                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12034                                 } else {
12035                                         EMIT_NEW_RETLOADA (cfg, ins);
12036                                 }
12037                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12038                                 
12039                                 if (sp != stack_start)
12040                                         UNVERIFIED;
12041                                 
12042                                 MONO_INST_NEW (cfg, ins, OP_BR);
12043                                 ins->inst_target_bb = end_bblock;
12044                                 MONO_ADD_INS (cfg->cbb, ins);
12045                                 link_bblock (cfg, cfg->cbb, end_bblock);
12046                                 start_new_bblock = 1;
12047                                 ip += 6;
12048                                 break;
12049                         }
12050                         case CEE_MONO_SAVE_LMF:
12051                         case CEE_MONO_RESTORE_LMF:
12052                                 ip += 2;
12053                                 break;
12054                         case CEE_MONO_CLASSCONST:
12055                                 CHECK_STACK_OVF (1);
12056                                 CHECK_OPSIZE (6);
12057                                 token = read32 (ip + 2);
12058                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12059                                 *sp++ = ins;
12060                                 ip += 6;
12061                                 inline_costs += 10 * num_calls++;
12062                                 break;
12063                         case CEE_MONO_NOT_TAKEN:
12064                                 cfg->cbb->out_of_line = TRUE;
12065                                 ip += 2;
12066                                 break;
12067                         case CEE_MONO_TLS: {
12068                                 MonoTlsKey key;
12069
12070                                 CHECK_STACK_OVF (1);
12071                                 CHECK_OPSIZE (6);
12072                                 key = (MonoTlsKey)read32 (ip + 2);
12073                                 g_assert (key < TLS_KEY_NUM);
12074
12075                                 ins = mono_create_tls_get (cfg, key);
12076                                 g_assert (ins);
12077                                 ins->type = STACK_PTR;
12078                                 *sp++ = ins;
12079                                 ip += 6;
12080                                 break;
12081                         }
12082                         case CEE_MONO_DYN_CALL: {
12083                                 MonoCallInst *call;
12084
12085                                 /* It would be easier to call a trampoline, but that would put an
12086                                  * extra frame on the stack, confusing exception handling. So
12087                                  * implement it inline using an opcode for now.
12088                                  */
12089
12090                                 if (!cfg->dyn_call_var) {
12091                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12092                                         /* prevent it from being register allocated */
12093                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12094                                 }
12095
12096                                 /* Has to use a call inst since it local regalloc expects it */
12097                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12098                                 ins = (MonoInst*)call;
12099                                 sp -= 2;
12100                                 ins->sreg1 = sp [0]->dreg;
12101                                 ins->sreg2 = sp [1]->dreg;
12102                                 MONO_ADD_INS (cfg->cbb, ins);
12103
12104                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12105
12106                                 ip += 2;
12107                                 inline_costs += 10 * num_calls++;
12108
12109                                 break;
12110                         }
12111                         case CEE_MONO_MEMORY_BARRIER: {
12112                                 CHECK_OPSIZE (6);
12113                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12114                                 ip += 6;
12115                                 break;
12116                         }
12117                         case CEE_MONO_ATOMIC_STORE_I4: {
12118                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
12119
12120                                 CHECK_OPSIZE (6);
12121                                 CHECK_STACK (2);
12122                                 sp -= 2;
12123
12124                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
12125                                 ins->dreg = sp [0]->dreg;
12126                                 ins->sreg1 = sp [1]->dreg;
12127                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
12128                                 MONO_ADD_INS (cfg->cbb, ins);
12129
12130                                 ip += 6;
12131                                 break;
12132                         }
12133                         case CEE_MONO_JIT_ATTACH: {
12134                                 MonoInst *args [16], *domain_ins;
12135                                 MonoInst *ad_ins, *jit_tls_ins;
12136                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12137
12138                                 g_assert (!mono_threads_is_coop_enabled ());
12139
12140                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12141
12142                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12143                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12144
12145                                 ad_ins = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
12146                                 jit_tls_ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
12147
12148                                 if (ad_ins && jit_tls_ins) {
12149                                         NEW_BBLOCK (cfg, next_bb);
12150                                         NEW_BBLOCK (cfg, call_bb);
12151
12152                                         if (cfg->compile_aot) {
12153                                                 /* AOT code is only used in the root domain */
12154                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12155                                         } else {
12156                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12157                                         }
12158                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12159                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12160
12161                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12162                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12163
12164                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12165                                         MONO_START_BB (cfg, call_bb);
12166                                 }
12167
12168                                 /* AOT code is only used in the root domain */
12169                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12170                                 if (cfg->compile_aot) {
12171                                         MonoInst *addr;
12172
12173                                         /*
12174                                          * This is called on unattached threads, so it cannot go through the trampoline
12175                                          * infrastructure. Use an indirect call through a got slot initialized at load time
12176                                          * instead.
12177                                          */
12178                                         EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_JIT_THREAD_ATTACH, NULL);
12179                                         ins = mono_emit_calli (cfg, helper_sig_jit_thread_attach, args, addr, NULL, NULL);
12180                                 } else {
12181                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12182                                 }
12183                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12184
12185                                 if (next_bb)
12186                                         MONO_START_BB (cfg, next_bb);
12187
12188                                 ip += 2;
12189                                 break;
12190                         }
12191                         case CEE_MONO_JIT_DETACH: {
12192                                 MonoInst *args [16];
12193
12194                                 /* Restore the original domain */
12195                                 dreg = alloc_ireg (cfg);
12196                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12197                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12198                                 ip += 2;
12199                                 break;
12200                         }
12201                         case CEE_MONO_CALLI_EXTRA_ARG: {
12202                                 MonoInst *addr;
12203                                 MonoMethodSignature *fsig;
12204                                 MonoInst *arg;
12205
12206                                 /*
12207                                  * This is the same as CEE_CALLI, but passes an additional argument
12208                                  * to the called method in llvmonly mode.
12209                                  * This is only used by delegate invoke wrappers to call the
12210                                  * actual delegate method.
12211                                  */
12212                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12213
12214                                 CHECK_OPSIZE (6);
12215                                 token = read32 (ip + 2);
12216
12217                                 ins = NULL;
12218
12219                                 cmethod = NULL;
12220                                 CHECK_STACK (1);
12221                                 --sp;
12222                                 addr = *sp;
12223                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12224                                 CHECK_CFG_ERROR;
12225
12226                                 if (cfg->llvm_only)
12227                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12228
12229                                 n = fsig->param_count + fsig->hasthis + 1;
12230
12231                                 CHECK_STACK (n);
12232
12233                                 sp -= n;
12234                                 arg = sp [n - 1];
12235
12236                                 if (cfg->llvm_only) {
12237                                         /*
12238                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12239                                          * cconv. This is set by mono_init_delegate ().
12240                                          */
12241                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12242                                                 MonoInst *callee = addr;
12243                                                 MonoInst *call, *localloc_ins;
12244                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12245                                                 int low_bit_reg = alloc_preg (cfg);
12246
12247                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12248                                                 NEW_BBLOCK (cfg, end_bb);
12249
12250                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12251                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12252                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12253
12254                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12255                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12256                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12257                                                 /*
12258                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12259                                                  */
12260                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12261                                                 ins->dreg = alloc_preg (cfg);
12262                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12263                                                 MONO_ADD_INS (cfg->cbb, ins);
12264                                                 localloc_ins = ins;
12265                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12266                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12267                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12268
12269                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12270                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12271
12272                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12273                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12274                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12275                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12276                                                 ins->dreg = call->dreg;
12277
12278                                                 MONO_START_BB (cfg, end_bb);
12279                                         } else {
12280                                                 /* Caller uses a normal calling conv */
12281
12282                                                 MonoInst *callee = addr;
12283                                                 MonoInst *call, *localloc_ins;
12284                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12285                                                 int low_bit_reg = alloc_preg (cfg);
12286
12287                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12288                                                 NEW_BBLOCK (cfg, end_bb);
12289
12290                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12291                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12292                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12293
12294                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12295                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12296                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12297                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12298                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12299                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12300                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12301                                                 MONO_ADD_INS (cfg->cbb, addr);
12302                                                 /*
12303                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12304                                                  */
12305                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12306                                                 ins->dreg = alloc_preg (cfg);
12307                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12308                                                 MONO_ADD_INS (cfg->cbb, ins);
12309                                                 localloc_ins = ins;
12310                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12311                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12312                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12313
12314                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12315                                                 ins->dreg = call->dreg;
12316                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12317
12318                                                 MONO_START_BB (cfg, end_bb);
12319                                         }
12320                                 } else {
12321                                         /* Same as CEE_CALLI */
12322                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12323                                                 /*
12324                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12325                                                  */
12326                                                 MonoInst *callee = addr;
12327
12328                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12329                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12330                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12331                                         } else {
12332                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12333                                         }
12334                                 }
12335
12336                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12337                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12338
12339                                 CHECK_CFG_EXCEPTION;
12340
12341                                 ip += 6;
12342                                 ins_flag = 0;
12343                                 constrained_class = NULL;
12344                                 break;
12345                         }
12346                         case CEE_MONO_LDDOMAIN:
12347                                 CHECK_STACK_OVF (1);
12348                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
12349                                 ip += 2;
12350                                 *sp++ = ins;
12351                                 break;
12352                         case CEE_MONO_GET_LAST_ERROR:
12353                                 CHECK_OPSIZE (2);
12354                                 CHECK_STACK_OVF (1);
12355
12356                                 MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
12357                                 ins->dreg = alloc_dreg (cfg, STACK_I4);
12358                                 ins->type = STACK_I4;
12359                                 MONO_ADD_INS (cfg->cbb, ins);
12360
12361                                 ip += 2;
12362                                 *sp++ = ins;
12363                                 break;
12364                         default:
12365                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12366                                 break;
12367                         }
12368                         break;
12369                 }
12370
12371                 case CEE_PREFIX1: {
12372                         CHECK_OPSIZE (2);
12373                         switch (ip [1]) {
12374                         case CEE_ARGLIST: {
12375                                 /* somewhat similar to LDTOKEN */
12376                                 MonoInst *addr, *vtvar;
12377                                 CHECK_STACK_OVF (1);
12378                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12379
12380                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12381                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12382
12383                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12384                                 ins->type = STACK_VTYPE;
12385                                 ins->klass = mono_defaults.argumenthandle_class;
12386                                 *sp++ = ins;
12387                                 ip += 2;
12388                                 break;
12389                         }
12390                         case CEE_CEQ:
12391                         case CEE_CGT:
12392                         case CEE_CGT_UN:
12393                         case CEE_CLT:
12394                         case CEE_CLT_UN: {
12395                                 MonoInst *cmp, *arg1, *arg2;
12396
12397                                 CHECK_STACK (2);
12398                                 sp -= 2;
12399                                 arg1 = sp [0];
12400                                 arg2 = sp [1];
12401
12402                                 /*
12403                                  * The following transforms:
12404                                  *    CEE_CEQ    into OP_CEQ
12405                                  *    CEE_CGT    into OP_CGT
12406                                  *    CEE_CGT_UN into OP_CGT_UN
12407                                  *    CEE_CLT    into OP_CLT
12408                                  *    CEE_CLT_UN into OP_CLT_UN
12409                                  */
12410                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12411
12412                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12413                                 cmp->sreg1 = arg1->dreg;
12414                                 cmp->sreg2 = arg2->dreg;
12415                                 type_from_op (cfg, cmp, arg1, arg2);
12416                                 CHECK_TYPE (cmp);
12417                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12418                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12419                                         cmp->opcode = OP_LCOMPARE;
12420                                 else if (arg1->type == STACK_R4)
12421                                         cmp->opcode = OP_RCOMPARE;
12422                                 else if (arg1->type == STACK_R8)
12423                                         cmp->opcode = OP_FCOMPARE;
12424                                 else
12425                                         cmp->opcode = OP_ICOMPARE;
12426                                 MONO_ADD_INS (cfg->cbb, cmp);
12427                                 ins->type = STACK_I4;
12428                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
12429                                 type_from_op (cfg, ins, arg1, arg2);
12430
12431                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12432                                         /*
12433                                          * The backends expect the fceq opcodes to do the
12434                                          * comparison too.
12435                                          */
12436                                         ins->sreg1 = cmp->sreg1;
12437                                         ins->sreg2 = cmp->sreg2;
12438                                         NULLIFY_INS (cmp);
12439                                 }
12440                                 MONO_ADD_INS (cfg->cbb, ins);
12441                                 *sp++ = ins;
12442                                 ip += 2;
12443                                 break;
12444                         }
12445                         case CEE_LDFTN: {
12446                                 MonoInst *argconst;
12447                                 MonoMethod *cil_method;
12448
12449                                 CHECK_STACK_OVF (1);
12450                                 CHECK_OPSIZE (6);
12451                                 n = read32 (ip + 2);
12452                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12453                                 CHECK_CFG_ERROR;
12454
12455                                 mono_class_init (cmethod->klass);
12456
12457                                 mono_save_token_info (cfg, image, n, cmethod);
12458
12459                                 context_used = mini_method_check_context_used (cfg, cmethod);
12460
12461                                 cil_method = cmethod;
12462                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12463                                         emit_method_access_failure (cfg, method, cil_method);
12464
12465                                 if (mono_security_core_clr_enabled ())
12466                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12467
12468                                 /* 
12469                                  * Optimize the common case of ldftn+delegate creation
12470                                  */
12471                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12472                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12473                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12474                                                 MonoInst *target_ins, *handle_ins;
12475                                                 MonoMethod *invoke;
12476                                                 int invoke_context_used;
12477
12478                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12479                                                 if (!invoke || !mono_method_signature (invoke))
12480                                                         LOAD_ERROR;
12481
12482                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12483
12484                                                 target_ins = sp [-1];
12485
12486                                                 if (mono_security_core_clr_enabled ())
12487                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12488
12489                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12490                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12491                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12492                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12493                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12494                                                         }
12495                                                 }
12496
12497                                                 /* FIXME: SGEN support */
12498                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12499                                                         ip += 6;
12500                                                         if (cfg->verbose_level > 3)
12501                                                                 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));
12502                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12503                                                                 sp --;
12504                                                                 *sp = handle_ins;
12505                                                                 CHECK_CFG_EXCEPTION;
12506                                                                 ip += 5;
12507                                                                 sp ++;
12508                                                                 break;
12509                                                         }
12510                                                         ip -= 6;
12511                                                 }
12512                                         }
12513                                 }
12514
12515                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12516                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12517                                 *sp++ = ins;
12518                                 
12519                                 ip += 6;
12520                                 inline_costs += 10 * num_calls++;
12521                                 break;
12522                         }
12523                         case CEE_LDVIRTFTN: {
12524                                 MonoInst *args [2];
12525
12526                                 CHECK_STACK (1);
12527                                 CHECK_OPSIZE (6);
12528                                 n = read32 (ip + 2);
12529                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12530                                 CHECK_CFG_ERROR;
12531
12532                                 mono_class_init (cmethod->klass);
12533  
12534                                 context_used = mini_method_check_context_used (cfg, cmethod);
12535
12536                                 if (mono_security_core_clr_enabled ())
12537                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12538
12539                                 /*
12540                                  * Optimize the common case of ldvirtftn+delegate creation
12541                                  */
12542                                 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)) {
12543                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12544                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12545                                                 MonoInst *target_ins, *handle_ins;
12546                                                 MonoMethod *invoke;
12547                                                 int invoke_context_used;
12548                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12549
12550                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12551                                                 if (!invoke || !mono_method_signature (invoke))
12552                                                         LOAD_ERROR;
12553
12554                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12555
12556                                                 target_ins = sp [-1];
12557
12558                                                 if (mono_security_core_clr_enabled ())
12559                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12560
12561                                                 /* FIXME: SGEN support */
12562                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12563                                                         ip += 6;
12564                                                         if (cfg->verbose_level > 3)
12565                                                                 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));
12566                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12567                                                                 sp -= 2;
12568                                                                 *sp = handle_ins;
12569                                                                 CHECK_CFG_EXCEPTION;
12570                                                                 ip += 5;
12571                                                                 sp ++;
12572                                                                 break;
12573                                                         }
12574                                                         ip -= 6;
12575                                                 }
12576                                         }
12577                                 }
12578
12579                                 --sp;
12580                                 args [0] = *sp;
12581
12582                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12583                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12584
12585                                 if (context_used)
12586                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12587                                 else
12588                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12589
12590                                 ip += 6;
12591                                 inline_costs += 10 * num_calls++;
12592                                 break;
12593                         }
12594                         case CEE_LDARG:
12595                                 CHECK_STACK_OVF (1);
12596                                 CHECK_OPSIZE (4);
12597                                 n = read16 (ip + 2);
12598                                 CHECK_ARG (n);
12599                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12600                                 *sp++ = ins;
12601                                 ip += 4;
12602                                 break;
12603                         case CEE_LDARGA:
12604                                 CHECK_STACK_OVF (1);
12605                                 CHECK_OPSIZE (4);
12606                                 n = read16 (ip + 2);
12607                                 CHECK_ARG (n);
12608                                 NEW_ARGLOADA (cfg, ins, n);
12609                                 MONO_ADD_INS (cfg->cbb, ins);
12610                                 *sp++ = ins;
12611                                 ip += 4;
12612                                 break;
12613                         case CEE_STARG:
12614                                 CHECK_STACK (1);
12615                                 --sp;
12616                                 CHECK_OPSIZE (4);
12617                                 n = read16 (ip + 2);
12618                                 CHECK_ARG (n);
12619                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12620                                         UNVERIFIED;
12621                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12622                                 ip += 4;
12623                                 break;
12624                         case CEE_LDLOC:
12625                                 CHECK_STACK_OVF (1);
12626                                 CHECK_OPSIZE (4);
12627                                 n = read16 (ip + 2);
12628                                 CHECK_LOCAL (n);
12629                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12630                                 *sp++ = ins;
12631                                 ip += 4;
12632                                 break;
12633                         case CEE_LDLOCA: {
12634                                 unsigned char *tmp_ip;
12635                                 CHECK_STACK_OVF (1);
12636                                 CHECK_OPSIZE (4);
12637                                 n = read16 (ip + 2);
12638                                 CHECK_LOCAL (n);
12639
12640                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12641                                         ip = tmp_ip;
12642                                         inline_costs += 1;
12643                                         break;
12644                                 }                       
12645                                 
12646                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12647                                 *sp++ = ins;
12648                                 ip += 4;
12649                                 break;
12650                         }
12651                         case CEE_STLOC:
12652                                 CHECK_STACK (1);
12653                                 --sp;
12654                                 CHECK_OPSIZE (4);
12655                                 n = read16 (ip + 2);
12656                                 CHECK_LOCAL (n);
12657                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12658                                         UNVERIFIED;
12659                                 emit_stloc_ir (cfg, sp, header, n);
12660                                 ip += 4;
12661                                 inline_costs += 1;
12662                                 break;
12663                         case CEE_LOCALLOC: {
12664                                 CHECK_STACK (1);
12665                                 MonoBasicBlock *non_zero_bb, *end_bb;
12666                                 int alloc_ptr = alloc_preg (cfg);
12667                                 --sp;
12668                                 if (sp != stack_start) 
12669                                         UNVERIFIED;
12670                                 if (cfg->method != method) 
12671                                         /* 
12672                                          * Inlining this into a loop in a parent could lead to 
12673                                          * stack overflows which is different behavior than the
12674                                          * non-inlined case, thus disable inlining in this case.
12675                                          */
12676                                         INLINE_FAILURE("localloc");
12677
12678                                 NEW_BBLOCK (cfg, non_zero_bb);
12679                                 NEW_BBLOCK (cfg, end_bb);
12680
12681                                 /* if size != zero */
12682                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
12683                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
12684
12685                                 //size is zero, so result is NULL
12686                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
12687                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12688
12689                                 MONO_START_BB (cfg, non_zero_bb);
12690                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12691                                 ins->dreg = alloc_ptr;
12692                                 ins->sreg1 = sp [0]->dreg;
12693                                 ins->type = STACK_PTR;
12694                                 MONO_ADD_INS (cfg->cbb, ins);
12695
12696                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12697                                 if (init_locals)
12698                                         ins->flags |= MONO_INST_INIT;
12699
12700                                 MONO_START_BB (cfg, end_bb);
12701                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
12702                                 ins->type = STACK_PTR;
12703
12704                                 *sp++ = ins;
12705                                 ip += 2;
12706                                 break;
12707                         }
12708                         case CEE_ENDFILTER: {
12709                                 MonoExceptionClause *clause, *nearest;
12710                                 int cc;
12711
12712                                 CHECK_STACK (1);
12713                                 --sp;
12714                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12715                                         UNVERIFIED;
12716                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12717                                 ins->sreg1 = (*sp)->dreg;
12718                                 MONO_ADD_INS (cfg->cbb, ins);
12719                                 start_new_bblock = 1;
12720                                 ip += 2;
12721
12722                                 nearest = NULL;
12723                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12724                                         clause = &header->clauses [cc];
12725                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12726                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12727                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12728                                                 nearest = clause;
12729                                 }
12730                                 g_assert (nearest);
12731                                 if ((ip - header->code) != nearest->handler_offset)
12732                                         UNVERIFIED;
12733
12734                                 break;
12735                         }
12736                         case CEE_UNALIGNED_:
12737                                 ins_flag |= MONO_INST_UNALIGNED;
12738                                 /* FIXME: record alignment? we can assume 1 for now */
12739                                 CHECK_OPSIZE (3);
12740                                 ip += 3;
12741                                 break;
12742                         case CEE_VOLATILE_:
12743                                 ins_flag |= MONO_INST_VOLATILE;
12744                                 ip += 2;
12745                                 break;
12746                         case CEE_TAIL_:
12747                                 ins_flag   |= MONO_INST_TAILCALL;
12748                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12749                                 /* Can't inline tail calls at this time */
12750                                 inline_costs += 100000;
12751                                 ip += 2;
12752                                 break;
12753                         case CEE_INITOBJ:
12754                                 CHECK_STACK (1);
12755                                 --sp;
12756                                 CHECK_OPSIZE (6);
12757                                 token = read32 (ip + 2);
12758                                 klass = mini_get_class (method, token, generic_context);
12759                                 CHECK_TYPELOAD (klass);
12760                                 if (generic_class_is_reference_type (cfg, klass))
12761                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12762                                 else
12763                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12764                                 ip += 6;
12765                                 inline_costs += 1;
12766                                 break;
12767                         case CEE_CONSTRAINED_:
12768                                 CHECK_OPSIZE (6);
12769                                 token = read32 (ip + 2);
12770                                 constrained_class = mini_get_class (method, token, generic_context);
12771                                 CHECK_TYPELOAD (constrained_class);
12772                                 ip += 6;
12773                                 break;
12774                         case CEE_CPBLK:
12775                         case CEE_INITBLK: {
12776                                 MonoInst *iargs [3];
12777                                 CHECK_STACK (3);
12778                                 sp -= 3;
12779
12780                                 /* Skip optimized paths for volatile operations. */
12781                                 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)) {
12782                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12783                                 } 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)) {
12784                                         /* emit_memset only works when val == 0 */
12785                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12786                                 } else {
12787                                         MonoInst *call;
12788                                         iargs [0] = sp [0];
12789                                         iargs [1] = sp [1];
12790                                         iargs [2] = sp [2];
12791                                         if (ip [1] == CEE_CPBLK) {
12792                                                 /*
12793                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12794                                                  * and release barriers for cpblk. It is technically both a load and
12795                                                  * store operation, so it seems like that's the sensible thing to do.
12796                                                  *
12797                                                  * FIXME: We emit full barriers on both sides of the operation for
12798                                                  * simplicity. We should have a separate atomic memcpy method instead.
12799                                                  */
12800                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12801
12802                                                 if (ins_flag & MONO_INST_VOLATILE)
12803                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12804
12805                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12806                                                 call->flags |= ins_flag;
12807
12808                                                 if (ins_flag & MONO_INST_VOLATILE)
12809                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12810                                         } else {
12811                                                 MonoMethod *memset_method = get_memset_method ();
12812                                                 if (ins_flag & MONO_INST_VOLATILE) {
12813                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12814                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12815                                                 }
12816                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12817                                                 call->flags |= ins_flag;
12818                                         }
12819                                 }
12820                                 ip += 2;
12821                                 ins_flag = 0;
12822                                 inline_costs += 1;
12823                                 break;
12824                         }
12825                         case CEE_NO_:
12826                                 CHECK_OPSIZE (3);
12827                                 if (ip [2] & 0x1)
12828                                         ins_flag |= MONO_INST_NOTYPECHECK;
12829                                 if (ip [2] & 0x2)
12830                                         ins_flag |= MONO_INST_NORANGECHECK;
12831                                 /* we ignore the no-nullcheck for now since we
12832                                  * really do it explicitly only when doing callvirt->call
12833                                  */
12834                                 ip += 3;
12835                                 break;
12836                         case CEE_RETHROW: {
12837                                 MonoInst *load;
12838                                 int handler_offset = -1;
12839
12840                                 for (i = 0; i < header->num_clauses; ++i) {
12841                                         MonoExceptionClause *clause = &header->clauses [i];
12842                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12843                                                 handler_offset = clause->handler_offset;
12844                                                 break;
12845                                         }
12846                                 }
12847
12848                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12849
12850                                 if (handler_offset == -1)
12851                                         UNVERIFIED;
12852
12853                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12854                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12855                                 ins->sreg1 = load->dreg;
12856                                 MONO_ADD_INS (cfg->cbb, ins);
12857
12858                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12859                                 MONO_ADD_INS (cfg->cbb, ins);
12860
12861                                 sp = stack_start;
12862                                 link_bblock (cfg, cfg->cbb, end_bblock);
12863                                 start_new_bblock = 1;
12864                                 ip += 2;
12865                                 break;
12866                         }
12867                         case CEE_SIZEOF: {
12868                                 guint32 val;
12869                                 int ialign;
12870
12871                                 CHECK_STACK_OVF (1);
12872                                 CHECK_OPSIZE (6);
12873                                 token = read32 (ip + 2);
12874                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12875                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12876                                         CHECK_CFG_ERROR;
12877
12878                                         val = mono_type_size (type, &ialign);
12879                                 } else {
12880                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12881                                         CHECK_TYPELOAD (klass);
12882
12883                                         val = mono_type_size (&klass->byval_arg, &ialign);
12884
12885                                         if (mini_is_gsharedvt_klass (klass))
12886                                                 GSHAREDVT_FAILURE (*ip);
12887                                 }
12888                                 EMIT_NEW_ICONST (cfg, ins, val);
12889                                 *sp++= ins;
12890                                 ip += 6;
12891                                 break;
12892                         }
12893                         case CEE_REFANYTYPE: {
12894                                 MonoInst *src_var, *src;
12895
12896                                 GSHAREDVT_FAILURE (*ip);
12897
12898                                 CHECK_STACK (1);
12899                                 --sp;
12900
12901                                 // FIXME:
12902                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12903                                 if (!src_var)
12904                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12905                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12906                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12907                                 *sp++ = ins;
12908                                 ip += 2;
12909                                 break;
12910                         }
12911                         case CEE_READONLY_:
12912                                 readonly = TRUE;
12913                                 ip += 2;
12914                                 break;
12915
12916                         case CEE_UNUSED56:
12917                         case CEE_UNUSED57:
12918                         case CEE_UNUSED70:
12919                         case CEE_UNUSED:
12920                         case CEE_UNUSED99:
12921                                 UNVERIFIED;
12922                                 
12923                         default:
12924                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12925                                 UNVERIFIED;
12926                         }
12927                         break;
12928                 }
12929                 case CEE_UNUSED58:
12930                 case CEE_UNUSED1:
12931                         UNVERIFIED;
12932
12933                 default:
12934                         g_warning ("opcode 0x%02x not handled", *ip);
12935                         UNVERIFIED;
12936                 }
12937         }
12938         if (start_new_bblock != 1)
12939                 UNVERIFIED;
12940
12941         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
12942         if (cfg->cbb->next_bb) {
12943                 /* This could already be set because of inlining, #693905 */
12944                 MonoBasicBlock *bb = cfg->cbb;
12945
12946                 while (bb->next_bb)
12947                         bb = bb->next_bb;
12948                 bb->next_bb = end_bblock;
12949         } else {
12950                 cfg->cbb->next_bb = end_bblock;
12951         }
12952
12953         if (cfg->method == method && cfg->domainvar) {
12954                 MonoInst *store;
12955                 MonoInst *get_domain;
12956
12957                 cfg->cbb = init_localsbb;
12958
12959                 get_domain = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
12960                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12961                 MONO_ADD_INS (cfg->cbb, store);
12962         }
12963
12964 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12965         if (cfg->compile_aot)
12966                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12967                 mono_get_got_var (cfg);
12968 #endif
12969
12970         if (cfg->method == method && cfg->got_var)
12971                 mono_emit_load_got_addr (cfg);
12972
12973         if (init_localsbb) {
12974                 cfg->cbb = init_localsbb;
12975                 cfg->ip = NULL;
12976                 for (i = 0; i < header->num_locals; ++i) {
12977                         emit_init_local (cfg, i, header->locals [i], init_locals);
12978                 }
12979         }
12980
12981         if (cfg->init_ref_vars && cfg->method == method) {
12982                 /* Emit initialization for ref vars */
12983                 // FIXME: Avoid duplication initialization for IL locals.
12984                 for (i = 0; i < cfg->num_varinfo; ++i) {
12985                         MonoInst *ins = cfg->varinfo [i];
12986
12987                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12988                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12989                 }
12990         }
12991
12992         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
12993                 cfg->cbb = init_localsbb;
12994                 emit_push_lmf (cfg);
12995         }
12996
12997         cfg->cbb = init_localsbb;
12998         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12999
13000         if (seq_points) {
13001                 MonoBasicBlock *bb;
13002
13003                 /*
13004                  * Make seq points at backward branch targets interruptable.
13005                  */
13006                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13007                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13008                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13009         }
13010
13011         /* Add a sequence point for method entry/exit events */
13012         if (seq_points && cfg->gen_sdb_seq_points) {
13013                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13014                 MONO_ADD_INS (init_localsbb, ins);
13015                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13016                 MONO_ADD_INS (cfg->bb_exit, ins);
13017         }
13018
13019         /*
13020          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13021          * the code they refer to was dead (#11880).
13022          */
13023         if (sym_seq_points) {
13024                 for (i = 0; i < header->code_size; ++i) {
13025                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13026                                 MonoInst *ins;
13027
13028                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13029                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13030                         }
13031                 }
13032         }
13033
13034         cfg->ip = NULL;
13035
13036         if (cfg->method == method) {
13037                 MonoBasicBlock *bb;
13038                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13039                         if (bb == cfg->bb_init)
13040                                 bb->region = -1;
13041                         else
13042                                 bb->region = mono_find_block_region (cfg, bb->real_offset);
13043                         if (cfg->spvars)
13044                                 mono_create_spvar_for_region (cfg, bb->region);
13045                         if (cfg->verbose_level > 2)
13046                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13047                 }
13048         } else {
13049                 MonoBasicBlock *bb;
13050                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
13051                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
13052                         bb->real_offset = inline_offset;
13053                 }
13054         }
13055
13056         if (inline_costs < 0) {
13057                 char *mname;
13058
13059                 /* Method is too large */
13060                 mname = mono_method_full_name (method, TRUE);
13061                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13062                 g_free (mname);
13063         }
13064
13065         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13066                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13067
13068         goto cleanup;
13069
13070 mono_error_exit:
13071         g_assert (!mono_error_ok (&cfg->error));
13072         goto cleanup;
13073  
13074  exception_exit:
13075         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13076         goto cleanup;
13077
13078  unverified:
13079         set_exception_type_from_invalid_il (cfg, method, ip);
13080         goto cleanup;
13081
13082  cleanup:
13083         g_slist_free (class_inits);
13084         mono_basic_block_free (original_bb);
13085         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13086         if (cfg->exception_type)
13087                 return -1;
13088         else
13089                 return inline_costs;
13090 }
13091
13092 static int
13093 store_membase_reg_to_store_membase_imm (int opcode)
13094 {
13095         switch (opcode) {
13096         case OP_STORE_MEMBASE_REG:
13097                 return OP_STORE_MEMBASE_IMM;
13098         case OP_STOREI1_MEMBASE_REG:
13099                 return OP_STOREI1_MEMBASE_IMM;
13100         case OP_STOREI2_MEMBASE_REG:
13101                 return OP_STOREI2_MEMBASE_IMM;
13102         case OP_STOREI4_MEMBASE_REG:
13103                 return OP_STOREI4_MEMBASE_IMM;
13104         case OP_STOREI8_MEMBASE_REG:
13105                 return OP_STOREI8_MEMBASE_IMM;
13106         default:
13107                 g_assert_not_reached ();
13108         }
13109
13110         return -1;
13111 }               
13112
13113 int
13114 mono_op_to_op_imm (int opcode)
13115 {
13116         switch (opcode) {
13117         case OP_IADD:
13118                 return OP_IADD_IMM;
13119         case OP_ISUB:
13120                 return OP_ISUB_IMM;
13121         case OP_IDIV:
13122                 return OP_IDIV_IMM;
13123         case OP_IDIV_UN:
13124                 return OP_IDIV_UN_IMM;
13125         case OP_IREM:
13126                 return OP_IREM_IMM;
13127         case OP_IREM_UN:
13128                 return OP_IREM_UN_IMM;
13129         case OP_IMUL:
13130                 return OP_IMUL_IMM;
13131         case OP_IAND:
13132                 return OP_IAND_IMM;
13133         case OP_IOR:
13134                 return OP_IOR_IMM;
13135         case OP_IXOR:
13136                 return OP_IXOR_IMM;
13137         case OP_ISHL:
13138                 return OP_ISHL_IMM;
13139         case OP_ISHR:
13140                 return OP_ISHR_IMM;
13141         case OP_ISHR_UN:
13142                 return OP_ISHR_UN_IMM;
13143
13144         case OP_LADD:
13145                 return OP_LADD_IMM;
13146         case OP_LSUB:
13147                 return OP_LSUB_IMM;
13148         case OP_LAND:
13149                 return OP_LAND_IMM;
13150         case OP_LOR:
13151                 return OP_LOR_IMM;
13152         case OP_LXOR:
13153                 return OP_LXOR_IMM;
13154         case OP_LSHL:
13155                 return OP_LSHL_IMM;
13156         case OP_LSHR:
13157                 return OP_LSHR_IMM;
13158         case OP_LSHR_UN:
13159                 return OP_LSHR_UN_IMM;
13160 #if SIZEOF_REGISTER == 8
13161         case OP_LREM:
13162                 return OP_LREM_IMM;
13163 #endif
13164
13165         case OP_COMPARE:
13166                 return OP_COMPARE_IMM;
13167         case OP_ICOMPARE:
13168                 return OP_ICOMPARE_IMM;
13169         case OP_LCOMPARE:
13170                 return OP_LCOMPARE_IMM;
13171
13172         case OP_STORE_MEMBASE_REG:
13173                 return OP_STORE_MEMBASE_IMM;
13174         case OP_STOREI1_MEMBASE_REG:
13175                 return OP_STOREI1_MEMBASE_IMM;
13176         case OP_STOREI2_MEMBASE_REG:
13177                 return OP_STOREI2_MEMBASE_IMM;
13178         case OP_STOREI4_MEMBASE_REG:
13179                 return OP_STOREI4_MEMBASE_IMM;
13180
13181 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13182         case OP_X86_PUSH:
13183                 return OP_X86_PUSH_IMM;
13184         case OP_X86_COMPARE_MEMBASE_REG:
13185                 return OP_X86_COMPARE_MEMBASE_IMM;
13186 #endif
13187 #if defined(TARGET_AMD64)
13188         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13189                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13190 #endif
13191         case OP_VOIDCALL_REG:
13192                 return OP_VOIDCALL;
13193         case OP_CALL_REG:
13194                 return OP_CALL;
13195         case OP_LCALL_REG:
13196                 return OP_LCALL;
13197         case OP_FCALL_REG:
13198                 return OP_FCALL;
13199         case OP_LOCALLOC:
13200                 return OP_LOCALLOC_IMM;
13201         }
13202
13203         return -1;
13204 }
13205
13206 static int
13207 ldind_to_load_membase (int opcode)
13208 {
13209         switch (opcode) {
13210         case CEE_LDIND_I1:
13211                 return OP_LOADI1_MEMBASE;
13212         case CEE_LDIND_U1:
13213                 return OP_LOADU1_MEMBASE;
13214         case CEE_LDIND_I2:
13215                 return OP_LOADI2_MEMBASE;
13216         case CEE_LDIND_U2:
13217                 return OP_LOADU2_MEMBASE;
13218         case CEE_LDIND_I4:
13219                 return OP_LOADI4_MEMBASE;
13220         case CEE_LDIND_U4:
13221                 return OP_LOADU4_MEMBASE;
13222         case CEE_LDIND_I:
13223                 return OP_LOAD_MEMBASE;
13224         case CEE_LDIND_REF:
13225                 return OP_LOAD_MEMBASE;
13226         case CEE_LDIND_I8:
13227                 return OP_LOADI8_MEMBASE;
13228         case CEE_LDIND_R4:
13229                 return OP_LOADR4_MEMBASE;
13230         case CEE_LDIND_R8:
13231                 return OP_LOADR8_MEMBASE;
13232         default:
13233                 g_assert_not_reached ();
13234         }
13235
13236         return -1;
13237 }
13238
13239 static int
13240 stind_to_store_membase (int opcode)
13241 {
13242         switch (opcode) {
13243         case CEE_STIND_I1:
13244                 return OP_STOREI1_MEMBASE_REG;
13245         case CEE_STIND_I2:
13246                 return OP_STOREI2_MEMBASE_REG;
13247         case CEE_STIND_I4:
13248                 return OP_STOREI4_MEMBASE_REG;
13249         case CEE_STIND_I:
13250         case CEE_STIND_REF:
13251                 return OP_STORE_MEMBASE_REG;
13252         case CEE_STIND_I8:
13253                 return OP_STOREI8_MEMBASE_REG;
13254         case CEE_STIND_R4:
13255                 return OP_STORER4_MEMBASE_REG;
13256         case CEE_STIND_R8:
13257                 return OP_STORER8_MEMBASE_REG;
13258         default:
13259                 g_assert_not_reached ();
13260         }
13261
13262         return -1;
13263 }
13264
13265 int
13266 mono_load_membase_to_load_mem (int opcode)
13267 {
13268         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13269 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13270         switch (opcode) {
13271         case OP_LOAD_MEMBASE:
13272                 return OP_LOAD_MEM;
13273         case OP_LOADU1_MEMBASE:
13274                 return OP_LOADU1_MEM;
13275         case OP_LOADU2_MEMBASE:
13276                 return OP_LOADU2_MEM;
13277         case OP_LOADI4_MEMBASE:
13278                 return OP_LOADI4_MEM;
13279         case OP_LOADU4_MEMBASE:
13280                 return OP_LOADU4_MEM;
13281 #if SIZEOF_REGISTER == 8
13282         case OP_LOADI8_MEMBASE:
13283                 return OP_LOADI8_MEM;
13284 #endif
13285         }
13286 #endif
13287
13288         return -1;
13289 }
13290
13291 static inline int
13292 op_to_op_dest_membase (int store_opcode, int opcode)
13293 {
13294 #if defined(TARGET_X86)
13295         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13296                 return -1;
13297
13298         switch (opcode) {
13299         case OP_IADD:
13300                 return OP_X86_ADD_MEMBASE_REG;
13301         case OP_ISUB:
13302                 return OP_X86_SUB_MEMBASE_REG;
13303         case OP_IAND:
13304                 return OP_X86_AND_MEMBASE_REG;
13305         case OP_IOR:
13306                 return OP_X86_OR_MEMBASE_REG;
13307         case OP_IXOR:
13308                 return OP_X86_XOR_MEMBASE_REG;
13309         case OP_ADD_IMM:
13310         case OP_IADD_IMM:
13311                 return OP_X86_ADD_MEMBASE_IMM;
13312         case OP_SUB_IMM:
13313         case OP_ISUB_IMM:
13314                 return OP_X86_SUB_MEMBASE_IMM;
13315         case OP_AND_IMM:
13316         case OP_IAND_IMM:
13317                 return OP_X86_AND_MEMBASE_IMM;
13318         case OP_OR_IMM:
13319         case OP_IOR_IMM:
13320                 return OP_X86_OR_MEMBASE_IMM;
13321         case OP_XOR_IMM:
13322         case OP_IXOR_IMM:
13323                 return OP_X86_XOR_MEMBASE_IMM;
13324         case OP_MOVE:
13325                 return OP_NOP;
13326         }
13327 #endif
13328
13329 #if defined(TARGET_AMD64)
13330         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13331                 return -1;
13332
13333         switch (opcode) {
13334         case OP_IADD:
13335                 return OP_X86_ADD_MEMBASE_REG;
13336         case OP_ISUB:
13337                 return OP_X86_SUB_MEMBASE_REG;
13338         case OP_IAND:
13339                 return OP_X86_AND_MEMBASE_REG;
13340         case OP_IOR:
13341                 return OP_X86_OR_MEMBASE_REG;
13342         case OP_IXOR:
13343                 return OP_X86_XOR_MEMBASE_REG;
13344         case OP_IADD_IMM:
13345                 return OP_X86_ADD_MEMBASE_IMM;
13346         case OP_ISUB_IMM:
13347                 return OP_X86_SUB_MEMBASE_IMM;
13348         case OP_IAND_IMM:
13349                 return OP_X86_AND_MEMBASE_IMM;
13350         case OP_IOR_IMM:
13351                 return OP_X86_OR_MEMBASE_IMM;
13352         case OP_IXOR_IMM:
13353                 return OP_X86_XOR_MEMBASE_IMM;
13354         case OP_LADD:
13355                 return OP_AMD64_ADD_MEMBASE_REG;
13356         case OP_LSUB:
13357                 return OP_AMD64_SUB_MEMBASE_REG;
13358         case OP_LAND:
13359                 return OP_AMD64_AND_MEMBASE_REG;
13360         case OP_LOR:
13361                 return OP_AMD64_OR_MEMBASE_REG;
13362         case OP_LXOR:
13363                 return OP_AMD64_XOR_MEMBASE_REG;
13364         case OP_ADD_IMM:
13365         case OP_LADD_IMM:
13366                 return OP_AMD64_ADD_MEMBASE_IMM;
13367         case OP_SUB_IMM:
13368         case OP_LSUB_IMM:
13369                 return OP_AMD64_SUB_MEMBASE_IMM;
13370         case OP_AND_IMM:
13371         case OP_LAND_IMM:
13372                 return OP_AMD64_AND_MEMBASE_IMM;
13373         case OP_OR_IMM:
13374         case OP_LOR_IMM:
13375                 return OP_AMD64_OR_MEMBASE_IMM;
13376         case OP_XOR_IMM:
13377         case OP_LXOR_IMM:
13378                 return OP_AMD64_XOR_MEMBASE_IMM;
13379         case OP_MOVE:
13380                 return OP_NOP;
13381         }
13382 #endif
13383
13384         return -1;
13385 }
13386
13387 static inline int
13388 op_to_op_store_membase (int store_opcode, int opcode)
13389 {
13390 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13391         switch (opcode) {
13392         case OP_ICEQ:
13393                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13394                         return OP_X86_SETEQ_MEMBASE;
13395         case OP_CNE:
13396                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13397                         return OP_X86_SETNE_MEMBASE;
13398         }
13399 #endif
13400
13401         return -1;
13402 }
13403
13404 static inline int
13405 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13406 {
13407 #ifdef TARGET_X86
13408         /* FIXME: This has sign extension issues */
13409         /*
13410         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13411                 return OP_X86_COMPARE_MEMBASE8_IMM;
13412         */
13413
13414         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13415                 return -1;
13416
13417         switch (opcode) {
13418         case OP_X86_PUSH:
13419                 return OP_X86_PUSH_MEMBASE;
13420         case OP_COMPARE_IMM:
13421         case OP_ICOMPARE_IMM:
13422                 return OP_X86_COMPARE_MEMBASE_IMM;
13423         case OP_COMPARE:
13424         case OP_ICOMPARE:
13425                 return OP_X86_COMPARE_MEMBASE_REG;
13426         }
13427 #endif
13428
13429 #ifdef TARGET_AMD64
13430         /* FIXME: This has sign extension issues */
13431         /*
13432         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13433                 return OP_X86_COMPARE_MEMBASE8_IMM;
13434         */
13435
13436         switch (opcode) {
13437         case OP_X86_PUSH:
13438                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13439                         return OP_X86_PUSH_MEMBASE;
13440                 break;
13441                 /* FIXME: This only works for 32 bit immediates
13442         case OP_COMPARE_IMM:
13443         case OP_LCOMPARE_IMM:
13444                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13445                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13446                 */
13447         case OP_ICOMPARE_IMM:
13448                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13449                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13450                 break;
13451         case OP_COMPARE:
13452         case OP_LCOMPARE:
13453                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
13454                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13455                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13456                         return OP_AMD64_COMPARE_MEMBASE_REG;
13457                 break;
13458         case OP_ICOMPARE:
13459                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13460                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13461                 break;
13462         }
13463 #endif
13464
13465         return -1;
13466 }
13467
13468 static inline int
13469 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
13470 {
13471 #ifdef TARGET_X86
13472         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13473                 return -1;
13474         
13475         switch (opcode) {
13476         case OP_COMPARE:
13477         case OP_ICOMPARE:
13478                 return OP_X86_COMPARE_REG_MEMBASE;
13479         case OP_IADD:
13480                 return OP_X86_ADD_REG_MEMBASE;
13481         case OP_ISUB:
13482                 return OP_X86_SUB_REG_MEMBASE;
13483         case OP_IAND:
13484                 return OP_X86_AND_REG_MEMBASE;
13485         case OP_IOR:
13486                 return OP_X86_OR_REG_MEMBASE;
13487         case OP_IXOR:
13488                 return OP_X86_XOR_REG_MEMBASE;
13489         }
13490 #endif
13491
13492 #ifdef TARGET_AMD64
13493         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
13494                 switch (opcode) {
13495                 case OP_ICOMPARE:
13496                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13497                 case OP_IADD:
13498                         return OP_X86_ADD_REG_MEMBASE;
13499                 case OP_ISUB:
13500                         return OP_X86_SUB_REG_MEMBASE;
13501                 case OP_IAND:
13502                         return OP_X86_AND_REG_MEMBASE;
13503                 case OP_IOR:
13504                         return OP_X86_OR_REG_MEMBASE;
13505                 case OP_IXOR:
13506                         return OP_X86_XOR_REG_MEMBASE;
13507                 }
13508         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
13509                 switch (opcode) {
13510                 case OP_COMPARE:
13511                 case OP_LCOMPARE:
13512                         return OP_AMD64_COMPARE_REG_MEMBASE;
13513                 case OP_LADD:
13514                         return OP_AMD64_ADD_REG_MEMBASE;
13515                 case OP_LSUB:
13516                         return OP_AMD64_SUB_REG_MEMBASE;
13517                 case OP_LAND:
13518                         return OP_AMD64_AND_REG_MEMBASE;
13519                 case OP_LOR:
13520                         return OP_AMD64_OR_REG_MEMBASE;
13521                 case OP_LXOR:
13522                         return OP_AMD64_XOR_REG_MEMBASE;
13523                 }
13524         }
13525 #endif
13526
13527         return -1;
13528 }
13529
13530 int
13531 mono_op_to_op_imm_noemul (int opcode)
13532 {
13533         switch (opcode) {
13534 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13535         case OP_LSHR:
13536         case OP_LSHL:
13537         case OP_LSHR_UN:
13538                 return -1;
13539 #endif
13540 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13541         case OP_IDIV:
13542         case OP_IDIV_UN:
13543         case OP_IREM:
13544         case OP_IREM_UN:
13545                 return -1;
13546 #endif
13547 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13548         case OP_IMUL:
13549                 return -1;
13550 #endif
13551         default:
13552                 return mono_op_to_op_imm (opcode);
13553         }
13554 }
13555
13556 /**
13557  * mono_handle_global_vregs:
13558  *
13559  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13560  * for them.
13561  */
13562 void
13563 mono_handle_global_vregs (MonoCompile *cfg)
13564 {
13565         gint32 *vreg_to_bb;
13566         MonoBasicBlock *bb;
13567         int i, pos;
13568
13569         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13570
13571 #ifdef MONO_ARCH_SIMD_INTRINSICS
13572         if (cfg->uses_simd_intrinsics)
13573                 mono_simd_simplify_indirection (cfg);
13574 #endif
13575
13576         /* Find local vregs used in more than one bb */
13577         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13578                 MonoInst *ins = bb->code;       
13579                 int block_num = bb->block_num;
13580
13581                 if (cfg->verbose_level > 2)
13582                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13583
13584                 cfg->cbb = bb;
13585                 for (; ins; ins = ins->next) {
13586                         const char *spec = INS_INFO (ins->opcode);
13587                         int regtype = 0, regindex;
13588                         gint32 prev_bb;
13589
13590                         if (G_UNLIKELY (cfg->verbose_level > 2))
13591                                 mono_print_ins (ins);
13592
13593                         g_assert (ins->opcode >= MONO_CEE_LAST);
13594
13595                         for (regindex = 0; regindex < 4; regindex ++) {
13596                                 int vreg = 0;
13597
13598                                 if (regindex == 0) {
13599                                         regtype = spec [MONO_INST_DEST];
13600                                         if (regtype == ' ')
13601                                                 continue;
13602                                         vreg = ins->dreg;
13603                                 } else if (regindex == 1) {
13604                                         regtype = spec [MONO_INST_SRC1];
13605                                         if (regtype == ' ')
13606                                                 continue;
13607                                         vreg = ins->sreg1;
13608                                 } else if (regindex == 2) {
13609                                         regtype = spec [MONO_INST_SRC2];
13610                                         if (regtype == ' ')
13611                                                 continue;
13612                                         vreg = ins->sreg2;
13613                                 } else if (regindex == 3) {
13614                                         regtype = spec [MONO_INST_SRC3];
13615                                         if (regtype == ' ')
13616                                                 continue;
13617                                         vreg = ins->sreg3;
13618                                 }
13619
13620 #if SIZEOF_REGISTER == 4
13621                                 /* In the LLVM case, the long opcodes are not decomposed */
13622                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13623                                         /*
13624                                          * Since some instructions reference the original long vreg,
13625                                          * and some reference the two component vregs, it is quite hard
13626                                          * to determine when it needs to be global. So be conservative.
13627                                          */
13628                                         if (!get_vreg_to_inst (cfg, vreg)) {
13629                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13630
13631                                                 if (cfg->verbose_level > 2)
13632                                                         printf ("LONG VREG R%d made global.\n", vreg);
13633                                         }
13634
13635                                         /*
13636                                          * Make the component vregs volatile since the optimizations can
13637                                          * get confused otherwise.
13638                                          */
13639                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
13640                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
13641                                 }
13642 #endif
13643
13644                                 g_assert (vreg != -1);
13645
13646                                 prev_bb = vreg_to_bb [vreg];
13647                                 if (prev_bb == 0) {
13648                                         /* 0 is a valid block num */
13649                                         vreg_to_bb [vreg] = block_num + 1;
13650                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13651                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13652                                                 continue;
13653
13654                                         if (!get_vreg_to_inst (cfg, vreg)) {
13655                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13656                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13657
13658                                                 switch (regtype) {
13659                                                 case 'i':
13660                                                         if (vreg_is_ref (cfg, vreg))
13661                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13662                                                         else
13663                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13664                                                         break;
13665                                                 case 'l':
13666                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13667                                                         break;
13668                                                 case 'f':
13669                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13670                                                         break;
13671                                                 case 'v':
13672                                                 case 'x':
13673                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13674                                                         break;
13675                                                 default:
13676                                                         g_assert_not_reached ();
13677                                                 }
13678                                         }
13679
13680                                         /* Flag as having been used in more than one bb */
13681                                         vreg_to_bb [vreg] = -1;
13682                                 }
13683                         }
13684                 }
13685         }
13686
13687         /* If a variable is used in only one bblock, convert it into a local vreg */
13688         for (i = 0; i < cfg->num_varinfo; i++) {
13689                 MonoInst *var = cfg->varinfo [i];
13690                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13691
13692                 switch (var->type) {
13693                 case STACK_I4:
13694                 case STACK_OBJ:
13695                 case STACK_PTR:
13696                 case STACK_MP:
13697                 case STACK_VTYPE:
13698 #if SIZEOF_REGISTER == 8
13699                 case STACK_I8:
13700 #endif
13701 #if !defined(TARGET_X86)
13702                 /* Enabling this screws up the fp stack on x86 */
13703                 case STACK_R8:
13704 #endif
13705                         if (mono_arch_is_soft_float ())
13706                                 break;
13707
13708                         /*
13709                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
13710                                 break;
13711                         */
13712
13713                         /* Arguments are implicitly global */
13714                         /* Putting R4 vars into registers doesn't work currently */
13715                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13716                         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) {
13717                                 /* 
13718                                  * Make that the variable's liveness interval doesn't contain a call, since
13719                                  * that would cause the lvreg to be spilled, making the whole optimization
13720                                  * useless.
13721                                  */
13722                                 /* This is too slow for JIT compilation */
13723 #if 0
13724                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13725                                         MonoInst *ins;
13726                                         int def_index, call_index, ins_index;
13727                                         gboolean spilled = FALSE;
13728
13729                                         def_index = -1;
13730                                         call_index = -1;
13731                                         ins_index = 0;
13732                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13733                                                 const char *spec = INS_INFO (ins->opcode);
13734
13735                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13736                                                         def_index = ins_index;
13737
13738                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13739                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13740                                                         if (call_index > def_index) {
13741                                                                 spilled = TRUE;
13742                                                                 break;
13743                                                         }
13744                                                 }
13745
13746                                                 if (MONO_IS_CALL (ins))
13747                                                         call_index = ins_index;
13748
13749                                                 ins_index ++;
13750                                         }
13751
13752                                         if (spilled)
13753                                                 break;
13754                                 }
13755 #endif
13756
13757                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13758                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13759                                 var->flags |= MONO_INST_IS_DEAD;
13760                                 cfg->vreg_to_inst [var->dreg] = NULL;
13761                         }
13762                         break;
13763                 }
13764         }
13765
13766         /* 
13767          * Compress the varinfo and vars tables so the liveness computation is faster and
13768          * takes up less space.
13769          */
13770         pos = 0;
13771         for (i = 0; i < cfg->num_varinfo; ++i) {
13772                 MonoInst *var = cfg->varinfo [i];
13773                 if (pos < i && cfg->locals_start == i)
13774                         cfg->locals_start = pos;
13775                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13776                         if (pos < i) {
13777                                 cfg->varinfo [pos] = cfg->varinfo [i];
13778                                 cfg->varinfo [pos]->inst_c0 = pos;
13779                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13780                                 cfg->vars [pos].idx = pos;
13781 #if SIZEOF_REGISTER == 4
13782                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13783                                         /* Modify the two component vars too */
13784                                         MonoInst *var1;
13785
13786                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
13787                                         var1->inst_c0 = pos;
13788                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
13789                                         var1->inst_c0 = pos;
13790                                 }
13791 #endif
13792                         }
13793                         pos ++;
13794                 }
13795         }
13796         cfg->num_varinfo = pos;
13797         if (cfg->locals_start > cfg->num_varinfo)
13798                 cfg->locals_start = cfg->num_varinfo;
13799 }
13800
13801 /*
13802  * mono_allocate_gsharedvt_vars:
13803  *
13804  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
13805  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
13806  */
13807 void
13808 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
13809 {
13810         int i;
13811
13812         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13813
13814         for (i = 0; i < cfg->num_varinfo; ++i) {
13815                 MonoInst *ins = cfg->varinfo [i];
13816                 int idx;
13817
13818                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13819                         if (i >= cfg->locals_start) {
13820                                 /* Local */
13821                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13822                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13823                                 ins->opcode = OP_GSHAREDVT_LOCAL;
13824                                 ins->inst_imm = idx;
13825                         } else {
13826                                 /* Arg */
13827                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
13828                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13829                         }
13830                 }
13831         }
13832 }
13833
13834 /**
13835  * mono_spill_global_vars:
13836  *
13837  *   Generate spill code for variables which are not allocated to registers, 
13838  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13839  * code is generated which could be optimized by the local optimization passes.
13840  */
13841 void
13842 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13843 {
13844         MonoBasicBlock *bb;
13845         char spec2 [16];
13846         int orig_next_vreg;
13847         guint32 *vreg_to_lvreg;
13848         guint32 *lvregs;
13849         guint32 i, lvregs_len, lvregs_size;
13850         gboolean dest_has_lvreg = FALSE;
13851         MonoStackType stacktypes [128];
13852         MonoInst **live_range_start, **live_range_end;
13853         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13854
13855         *need_local_opts = FALSE;
13856
13857         memset (spec2, 0, sizeof (spec2));
13858
13859         /* FIXME: Move this function to mini.c */
13860         stacktypes ['i'] = STACK_PTR;
13861         stacktypes ['l'] = STACK_I8;
13862         stacktypes ['f'] = STACK_R8;
13863 #ifdef MONO_ARCH_SIMD_INTRINSICS
13864         stacktypes ['x'] = STACK_VTYPE;
13865 #endif
13866
13867 #if SIZEOF_REGISTER == 4
13868         /* Create MonoInsts for longs */
13869         for (i = 0; i < cfg->num_varinfo; i++) {
13870                 MonoInst *ins = cfg->varinfo [i];
13871
13872                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13873                         switch (ins->type) {
13874                         case STACK_R8:
13875                         case STACK_I8: {
13876                                 MonoInst *tree;
13877
13878                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13879                                         break;
13880
13881                                 g_assert (ins->opcode == OP_REGOFFSET);
13882
13883                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
13884                                 g_assert (tree);
13885                                 tree->opcode = OP_REGOFFSET;
13886                                 tree->inst_basereg = ins->inst_basereg;
13887                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13888
13889                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
13890                                 g_assert (tree);
13891                                 tree->opcode = OP_REGOFFSET;
13892                                 tree->inst_basereg = ins->inst_basereg;
13893                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13894                                 break;
13895                         }
13896                         default:
13897                                 break;
13898                         }
13899                 }
13900         }
13901 #endif
13902
13903         if (cfg->compute_gc_maps) {
13904                 /* registers need liveness info even for !non refs */
13905                 for (i = 0; i < cfg->num_varinfo; i++) {
13906                         MonoInst *ins = cfg->varinfo [i];
13907
13908                         if (ins->opcode == OP_REGVAR)
13909                                 ins->flags |= MONO_INST_GC_TRACK;
13910                 }
13911         }
13912                 
13913         /* FIXME: widening and truncation */
13914
13915         /*
13916          * As an optimization, when a variable allocated to the stack is first loaded into 
13917          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13918          * the variable again.
13919          */
13920         orig_next_vreg = cfg->next_vreg;
13921         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13922         lvregs_size = 1024;
13923         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * lvregs_size);
13924         lvregs_len = 0;
13925
13926         /* 
13927          * These arrays contain the first and last instructions accessing a given
13928          * variable.
13929          * Since we emit bblocks in the same order we process them here, and we
13930          * don't split live ranges, these will precisely describe the live range of
13931          * the variable, i.e. the instruction range where a valid value can be found
13932          * in the variables location.
13933          * The live range is computed using the liveness info computed by the liveness pass.
13934          * We can't use vmv->range, since that is an abstract live range, and we need
13935          * one which is instruction precise.
13936          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13937          */
13938         /* FIXME: Only do this if debugging info is requested */
13939         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13940         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13941         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13942         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13943         
13944         /* Add spill loads/stores */
13945         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13946                 MonoInst *ins;
13947
13948                 if (cfg->verbose_level > 2)
13949                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13950
13951                 /* Clear vreg_to_lvreg array */
13952                 for (i = 0; i < lvregs_len; i++)
13953                         vreg_to_lvreg [lvregs [i]] = 0;
13954                 lvregs_len = 0;
13955
13956                 cfg->cbb = bb;
13957                 MONO_BB_FOR_EACH_INS (bb, ins) {
13958                         const char *spec = INS_INFO (ins->opcode);
13959                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13960                         gboolean store, no_lvreg;
13961                         int sregs [MONO_MAX_SRC_REGS];
13962
13963                         if (G_UNLIKELY (cfg->verbose_level > 2))
13964                                 mono_print_ins (ins);
13965
13966                         if (ins->opcode == OP_NOP)
13967                                 continue;
13968
13969                         /* 
13970                          * We handle LDADDR here as well, since it can only be decomposed
13971                          * when variable addresses are known.
13972                          */
13973                         if (ins->opcode == OP_LDADDR) {
13974                                 MonoInst *var = (MonoInst *)ins->inst_p0;
13975
13976                                 if (var->opcode == OP_VTARG_ADDR) {
13977                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13978                                         MonoInst *vtaddr = var->inst_left;
13979                                         if (vtaddr->opcode == OP_REGVAR) {
13980                                                 ins->opcode = OP_MOVE;
13981                                                 ins->sreg1 = vtaddr->dreg;
13982                                         }
13983                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13984                                                 ins->opcode = OP_LOAD_MEMBASE;
13985                                                 ins->inst_basereg = vtaddr->inst_basereg;
13986                                                 ins->inst_offset = vtaddr->inst_offset;
13987                                         } else
13988                                                 NOT_IMPLEMENTED;
13989                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
13990                                         /* gsharedvt arg passed by ref */
13991                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13992
13993                                         ins->opcode = OP_LOAD_MEMBASE;
13994                                         ins->inst_basereg = var->inst_basereg;
13995                                         ins->inst_offset = var->inst_offset;
13996                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
13997                                         MonoInst *load, *load2, *load3;
13998                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
13999                                         int reg1, reg2, reg3;
14000                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14001                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14002
14003                                         /*
14004                                          * gsharedvt local.
14005                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14006                                          */
14007
14008                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14009
14010                                         g_assert (info_var);
14011                                         g_assert (locals_var);
14012
14013                                         /* Mark the instruction used to compute the locals var as used */
14014                                         cfg->gsharedvt_locals_var_ins = NULL;
14015
14016                                         /* Load the offset */
14017                                         if (info_var->opcode == OP_REGOFFSET) {
14018                                                 reg1 = alloc_ireg (cfg);
14019                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14020                                         } else if (info_var->opcode == OP_REGVAR) {
14021                                                 load = NULL;
14022                                                 reg1 = info_var->dreg;
14023                                         } else {
14024                                                 g_assert_not_reached ();
14025                                         }
14026                                         reg2 = alloc_ireg (cfg);
14027                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14028                                         /* Load the locals area address */
14029                                         reg3 = alloc_ireg (cfg);
14030                                         if (locals_var->opcode == OP_REGOFFSET) {
14031                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14032                                         } else if (locals_var->opcode == OP_REGVAR) {
14033                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14034                                         } else {
14035                                                 g_assert_not_reached ();
14036                                         }
14037                                         /* Compute the address */
14038                                         ins->opcode = OP_PADD;
14039                                         ins->sreg1 = reg3;
14040                                         ins->sreg2 = reg2;
14041
14042                                         mono_bblock_insert_before_ins (bb, ins, load3);
14043                                         mono_bblock_insert_before_ins (bb, load3, load2);
14044                                         if (load)
14045                                                 mono_bblock_insert_before_ins (bb, load2, load);
14046                                 } else {
14047                                         g_assert (var->opcode == OP_REGOFFSET);
14048
14049                                         ins->opcode = OP_ADD_IMM;
14050                                         ins->sreg1 = var->inst_basereg;
14051                                         ins->inst_imm = var->inst_offset;
14052                                 }
14053
14054                                 *need_local_opts = TRUE;
14055                                 spec = INS_INFO (ins->opcode);
14056                         }
14057
14058                         if (ins->opcode < MONO_CEE_LAST) {
14059                                 mono_print_ins (ins);
14060                                 g_assert_not_reached ();
14061                         }
14062
14063                         /*
14064                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14065                          * src register.
14066                          * FIXME:
14067                          */
14068                         if (MONO_IS_STORE_MEMBASE (ins)) {
14069                                 tmp_reg = ins->dreg;
14070                                 ins->dreg = ins->sreg2;
14071                                 ins->sreg2 = tmp_reg;
14072                                 store = TRUE;
14073
14074                                 spec2 [MONO_INST_DEST] = ' ';
14075                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14076                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14077                                 spec2 [MONO_INST_SRC3] = ' ';
14078                                 spec = spec2;
14079                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14080                                 g_assert_not_reached ();
14081                         else
14082                                 store = FALSE;
14083                         no_lvreg = FALSE;
14084
14085                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14086                                 printf ("\t %.3s %d", spec, ins->dreg);
14087                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14088                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14089                                         printf (" %d", sregs [srcindex]);
14090                                 printf ("\n");
14091                         }
14092
14093                         /***************/
14094                         /*    DREG     */
14095                         /***************/
14096                         regtype = spec [MONO_INST_DEST];
14097                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14098                         prev_dreg = -1;
14099
14100                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14101                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14102                                 MonoInst *store_ins;
14103                                 int store_opcode;
14104                                 MonoInst *def_ins = ins;
14105                                 int dreg = ins->dreg; /* The original vreg */
14106
14107                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14108
14109                                 if (var->opcode == OP_REGVAR) {
14110                                         ins->dreg = var->dreg;
14111                                 } 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)) {
14112                                         /* 
14113                                          * Instead of emitting a load+store, use a _membase opcode.
14114                                          */
14115                                         g_assert (var->opcode == OP_REGOFFSET);
14116                                         if (ins->opcode == OP_MOVE) {
14117                                                 NULLIFY_INS (ins);
14118                                                 def_ins = NULL;
14119                                         } else {
14120                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14121                                                 ins->inst_basereg = var->inst_basereg;
14122                                                 ins->inst_offset = var->inst_offset;
14123                                                 ins->dreg = -1;
14124                                         }
14125                                         spec = INS_INFO (ins->opcode);
14126                                 } else {
14127                                         guint32 lvreg;
14128
14129                                         g_assert (var->opcode == OP_REGOFFSET);
14130
14131                                         prev_dreg = ins->dreg;
14132
14133                                         /* Invalidate any previous lvreg for this vreg */
14134                                         vreg_to_lvreg [ins->dreg] = 0;
14135
14136                                         lvreg = 0;
14137
14138                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14139                                                 regtype = 'l';
14140                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14141                                         }
14142
14143                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14144
14145 #if SIZEOF_REGISTER != 8
14146                                         if (regtype == 'l') {
14147                                                 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));
14148                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14149                                                 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));
14150                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14151                                                 def_ins = store_ins;
14152                                         }
14153                                         else
14154 #endif
14155                                         {
14156                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14157
14158                                                 /* Try to fuse the store into the instruction itself */
14159                                                 /* FIXME: Add more instructions */
14160                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14161                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14162                                                         ins->inst_imm = ins->inst_c0;
14163                                                         ins->inst_destbasereg = var->inst_basereg;
14164                                                         ins->inst_offset = var->inst_offset;
14165                                                         spec = INS_INFO (ins->opcode);
14166                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14167                                                         ins->opcode = store_opcode;
14168                                                         ins->inst_destbasereg = var->inst_basereg;
14169                                                         ins->inst_offset = var->inst_offset;
14170
14171                                                         no_lvreg = TRUE;
14172
14173                                                         tmp_reg = ins->dreg;
14174                                                         ins->dreg = ins->sreg2;
14175                                                         ins->sreg2 = tmp_reg;
14176                                                         store = TRUE;
14177
14178                                                         spec2 [MONO_INST_DEST] = ' ';
14179                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14180                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14181                                                         spec2 [MONO_INST_SRC3] = ' ';
14182                                                         spec = spec2;
14183                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14184                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14185                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14186                                                         ins->dreg = -1;
14187                                                         ins->inst_basereg = var->inst_basereg;
14188                                                         ins->inst_offset = var->inst_offset;
14189                                                         spec = INS_INFO (ins->opcode);
14190                                                 } else {
14191                                                         /* printf ("INS: "); mono_print_ins (ins); */
14192                                                         /* Create a store instruction */
14193                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14194
14195                                                         /* Insert it after the instruction */
14196                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14197
14198                                                         def_ins = store_ins;
14199
14200                                                         /* 
14201                                                          * We can't assign ins->dreg to var->dreg here, since the
14202                                                          * sregs could use it. So set a flag, and do it after
14203                                                          * the sregs.
14204                                                          */
14205                                                         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)))
14206                                                                 dest_has_lvreg = TRUE;
14207                                                 }
14208                                         }
14209                                 }
14210
14211                                 if (def_ins && !live_range_start [dreg]) {
14212                                         live_range_start [dreg] = def_ins;
14213                                         live_range_start_bb [dreg] = bb;
14214                                 }
14215
14216                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14217                                         MonoInst *tmp;
14218
14219                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14220                                         tmp->inst_c1 = dreg;
14221                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14222                                 }
14223                         }
14224
14225                         /************/
14226                         /*  SREGS   */
14227                         /************/
14228                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14229                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14230                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14231                                 sreg = sregs [srcindex];
14232
14233                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14234                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14235                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14236                                         MonoInst *use_ins = ins;
14237                                         MonoInst *load_ins;
14238                                         guint32 load_opcode;
14239
14240                                         if (var->opcode == OP_REGVAR) {
14241                                                 sregs [srcindex] = var->dreg;
14242                                                 //mono_inst_set_src_registers (ins, sregs);
14243                                                 live_range_end [sreg] = use_ins;
14244                                                 live_range_end_bb [sreg] = bb;
14245
14246                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14247                                                         MonoInst *tmp;
14248
14249                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14250                                                         /* var->dreg is a hreg */
14251                                                         tmp->inst_c1 = sreg;
14252                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14253                                                 }
14254
14255                                                 continue;
14256                                         }
14257
14258                                         g_assert (var->opcode == OP_REGOFFSET);
14259                                                 
14260                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14261
14262                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14263
14264                                         if (vreg_to_lvreg [sreg]) {
14265                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14266
14267                                                 /* The variable is already loaded to an lvreg */
14268                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14269                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14270                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14271                                                 //mono_inst_set_src_registers (ins, sregs);
14272                                                 continue;
14273                                         }
14274
14275                                         /* Try to fuse the load into the instruction */
14276                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14277                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14278                                                 sregs [0] = var->inst_basereg;
14279                                                 //mono_inst_set_src_registers (ins, sregs);
14280                                                 ins->inst_offset = var->inst_offset;
14281                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14282                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14283                                                 sregs [1] = var->inst_basereg;
14284                                                 //mono_inst_set_src_registers (ins, sregs);
14285                                                 ins->inst_offset = var->inst_offset;
14286                                         } else {
14287                                                 if (MONO_IS_REAL_MOVE (ins)) {
14288                                                         ins->opcode = OP_NOP;
14289                                                         sreg = ins->dreg;
14290                                                 } else {
14291                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14292
14293                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14294
14295                                                         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) {
14296                                                                 if (var->dreg == prev_dreg) {
14297                                                                         /*
14298                                                                          * sreg refers to the value loaded by the load
14299                                                                          * emitted below, but we need to use ins->dreg
14300                                                                          * since it refers to the store emitted earlier.
14301                                                                          */
14302                                                                         sreg = ins->dreg;
14303                                                                 }
14304                                                                 g_assert (sreg != -1);
14305                                                                 vreg_to_lvreg [var->dreg] = sreg;
14306                                                                 if (lvregs_len >= lvregs_size) {
14307                                                                         guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
14308                                                                         memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
14309                                                                         lvregs = new_lvregs;
14310                                                                         lvregs_size *= 2;
14311                                                                 }
14312                                                                 lvregs [lvregs_len ++] = var->dreg;
14313                                                         }
14314                                                 }
14315
14316                                                 sregs [srcindex] = sreg;
14317                                                 //mono_inst_set_src_registers (ins, sregs);
14318
14319 #if SIZEOF_REGISTER != 8
14320                                                 if (regtype == 'l') {
14321                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14322                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14323                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14324                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14325                                                         use_ins = load_ins;
14326                                                 }
14327                                                 else
14328 #endif
14329                                                 {
14330 #if SIZEOF_REGISTER == 4
14331                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14332 #endif
14333                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14334                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14335                                                         use_ins = load_ins;
14336                                                 }
14337                                         }
14338
14339                                         if (var->dreg < orig_next_vreg) {
14340                                                 live_range_end [var->dreg] = use_ins;
14341                                                 live_range_end_bb [var->dreg] = bb;
14342                                         }
14343
14344                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14345                                                 MonoInst *tmp;
14346
14347                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14348                                                 tmp->inst_c1 = var->dreg;
14349                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14350                                         }
14351                                 }
14352                         }
14353                         mono_inst_set_src_registers (ins, sregs);
14354
14355                         if (dest_has_lvreg) {
14356                                 g_assert (ins->dreg != -1);
14357                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14358                                 if (lvregs_len >= lvregs_size) {
14359                                         guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
14360                                         memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
14361                                         lvregs = new_lvregs;
14362                                         lvregs_size *= 2;
14363                                 }
14364                                 lvregs [lvregs_len ++] = prev_dreg;
14365                                 dest_has_lvreg = FALSE;
14366                         }
14367
14368                         if (store) {
14369                                 tmp_reg = ins->dreg;
14370                                 ins->dreg = ins->sreg2;
14371                                 ins->sreg2 = tmp_reg;
14372                         }
14373
14374                         if (MONO_IS_CALL (ins)) {
14375                                 /* Clear vreg_to_lvreg array */
14376                                 for (i = 0; i < lvregs_len; i++)
14377                                         vreg_to_lvreg [lvregs [i]] = 0;
14378                                 lvregs_len = 0;
14379                         } else if (ins->opcode == OP_NOP) {
14380                                 ins->dreg = -1;
14381                                 MONO_INST_NULLIFY_SREGS (ins);
14382                         }
14383
14384                         if (cfg->verbose_level > 2)
14385                                 mono_print_ins_index (1, ins);
14386                 }
14387
14388                 /* Extend the live range based on the liveness info */
14389                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14390                         for (i = 0; i < cfg->num_varinfo; i ++) {
14391                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14392
14393                                 if (vreg_is_volatile (cfg, vi->vreg))
14394                                         /* The liveness info is incomplete */
14395                                         continue;
14396
14397                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14398                                         /* Live from at least the first ins of this bb */
14399                                         live_range_start [vi->vreg] = bb->code;
14400                                         live_range_start_bb [vi->vreg] = bb;
14401                                 }
14402
14403                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14404                                         /* Live at least until the last ins of this bb */
14405                                         live_range_end [vi->vreg] = bb->last_ins;
14406                                         live_range_end_bb [vi->vreg] = bb;
14407                                 }
14408                         }
14409                 }
14410         }
14411         
14412         /*
14413          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14414          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14415          */
14416         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14417                 for (i = 0; i < cfg->num_varinfo; ++i) {
14418                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14419                         MonoInst *ins;
14420
14421                         if (live_range_start [vreg]) {
14422                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14423                                 ins->inst_c0 = i;
14424                                 ins->inst_c1 = vreg;
14425                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14426                         }
14427                         if (live_range_end [vreg]) {
14428                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14429                                 ins->inst_c0 = i;
14430                                 ins->inst_c1 = vreg;
14431                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14432                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14433                                 else
14434                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14435                         }
14436                 }
14437         }
14438
14439         if (cfg->gsharedvt_locals_var_ins) {
14440                 /* Nullify if unused */
14441                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14442                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14443         }
14444
14445         g_free (live_range_start);
14446         g_free (live_range_end);
14447         g_free (live_range_start_bb);
14448         g_free (live_range_end_bb);
14449 }
14450
14451
14452 /**
14453  * FIXME:
14454  * - use 'iadd' instead of 'int_add'
14455  * - handling ovf opcodes: decompose in method_to_ir.
14456  * - unify iregs/fregs
14457  *   -> partly done, the missing parts are:
14458  *   - a more complete unification would involve unifying the hregs as well, so
14459  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14460  *     would no longer map to the machine hregs, so the code generators would need to
14461  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14462  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14463  *     fp/non-fp branches speeds it up by about 15%.
14464  * - use sext/zext opcodes instead of shifts
14465  * - add OP_ICALL
14466  * - get rid of TEMPLOADs if possible and use vregs instead
14467  * - clean up usage of OP_P/OP_ opcodes
14468  * - cleanup usage of DUMMY_USE
14469  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14470  *   stack
14471  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14472  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14473  * - make sure handle_stack_args () is called before the branch is emitted
14474  * - when the new IR is done, get rid of all unused stuff
14475  * - COMPARE/BEQ as separate instructions or unify them ?
14476  *   - keeping them separate allows specialized compare instructions like
14477  *     compare_imm, compare_membase
14478  *   - most back ends unify fp compare+branch, fp compare+ceq
14479  * - integrate mono_save_args into inline_method
14480  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14481  * - handle long shift opts on 32 bit platforms somehow: they require 
14482  *   3 sregs (2 for arg1 and 1 for arg2)
14483  * - make byref a 'normal' type.
14484  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14485  *   variable if needed.
14486  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14487  *   like inline_method.
14488  * - remove inlining restrictions
14489  * - fix LNEG and enable cfold of INEG
14490  * - generalize x86 optimizations like ldelema as a peephole optimization
14491  * - add store_mem_imm for amd64
14492  * - optimize the loading of the interruption flag in the managed->native wrappers
14493  * - avoid special handling of OP_NOP in passes
14494  * - move code inserting instructions into one function/macro.
14495  * - try a coalescing phase after liveness analysis
14496  * - add float -> vreg conversion + local optimizations on !x86
14497  * - figure out how to handle decomposed branches during optimizations, ie.
14498  *   compare+branch, op_jump_table+op_br etc.
14499  * - promote RuntimeXHandles to vregs
14500  * - vtype cleanups:
14501  *   - add a NEW_VARLOADA_VREG macro
14502  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14503  *   accessing vtype fields.
14504  * - get rid of I8CONST on 64 bit platforms
14505  * - dealing with the increase in code size due to branches created during opcode
14506  *   decomposition:
14507  *   - use extended basic blocks
14508  *     - all parts of the JIT
14509  *     - handle_global_vregs () && local regalloc
14510  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14511  * - sources of increase in code size:
14512  *   - vtypes
14513  *   - long compares
14514  *   - isinst and castclass
14515  *   - lvregs not allocated to global registers even if used multiple times
14516  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14517  *   meaningful.
14518  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14519  * - add all micro optimizations from the old JIT
14520  * - put tree optimizations into the deadce pass
14521  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14522  *   specific function.
14523  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14524  *   fcompare + branchCC.
14525  * - create a helper function for allocating a stack slot, taking into account 
14526  *   MONO_CFG_HAS_SPILLUP.
14527  * - merge r68207.
14528  * - merge the ia64 switch changes.
14529  * - optimize mono_regstate2_alloc_int/float.
14530  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14531  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14532  *   parts of the tree could be separated by other instructions, killing the tree
14533  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14534  *   instructions if the result of the load is used multiple times ?
14535  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14536  * - LAST MERGE: 108395.
14537  * - when returning vtypes in registers, generate IR and append it to the end of the
14538  *   last bb instead of doing it in the epilog.
14539  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14540  */
14541
14542 /*
14543
14544 NOTES
14545 -----
14546
14547 - When to decompose opcodes:
14548   - earlier: this makes some optimizations hard to implement, since the low level IR
14549   no longer contains the neccessary information. But it is easier to do.
14550   - later: harder to implement, enables more optimizations.
14551 - Branches inside bblocks:
14552   - created when decomposing complex opcodes. 
14553     - branches to another bblock: harmless, but not tracked by the branch 
14554       optimizations, so need to branch to a label at the start of the bblock.
14555     - branches to inside the same bblock: very problematic, trips up the local
14556       reg allocator. Can be fixed by spitting the current bblock, but that is a
14557       complex operation, since some local vregs can become global vregs etc.
14558 - Local/global vregs:
14559   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14560     local register allocator.
14561   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14562     structure, created by mono_create_var (). Assigned to hregs or the stack by
14563     the global register allocator.
14564 - When to do optimizations like alu->alu_imm:
14565   - earlier -> saves work later on since the IR will be smaller/simpler
14566   - later -> can work on more instructions
14567 - Handling of valuetypes:
14568   - When a vtype is pushed on the stack, a new temporary is created, an 
14569     instruction computing its address (LDADDR) is emitted and pushed on
14570     the stack. Need to optimize cases when the vtype is used immediately as in
14571     argument passing, stloc etc.
14572 - Instead of the to_end stuff in the old JIT, simply call the function handling
14573   the values on the stack before emitting the last instruction of the bb.
14574 */
14575
14576 #else /* !DISABLE_JIT */
14577
14578 void
14579 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
14580 {
14581 }
14582
14583 #endif /* !DISABLE_JIT */