Merge pull request #4433 from kumpera/android-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
17 #ifndef DISABLE_JIT
18
19 #include <signal.h>
20
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24
25 #include <math.h>
26 #include <string.h>
27 #include <ctype.h>
28
29 #ifdef HAVE_SYS_TIME_H
30 #include <sys/time.h>
31 #endif
32
33 #ifdef HAVE_ALLOCA_H
34 #include <alloca.h>
35 #endif
36
37 #include <mono/utils/memcheck.h>
38 #include "mini.h"
39 #include <mono/metadata/abi-details.h>
40 #include <mono/metadata/assembly.h>
41 #include <mono/metadata/attrdefs.h>
42 #include <mono/metadata/loader.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/class.h>
45 #include <mono/metadata/object.h>
46 #include <mono/metadata/exception.h>
47 #include <mono/metadata/opcodes.h>
48 #include <mono/metadata/mono-endian.h>
49 #include <mono/metadata/tokentype.h>
50 #include <mono/metadata/tabledefs.h>
51 #include <mono/metadata/marshal.h>
52 #include <mono/metadata/debug-helpers.h>
53 #include <mono/metadata/mono-debug.h>
54 #include <mono/metadata/mono-debug-debugger.h>
55 #include <mono/metadata/gc-internals.h>
56 #include <mono/metadata/security-manager.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/security-core-clr.h>
59 #include <mono/metadata/profiler-private.h>
60 #include <mono/metadata/profiler.h>
61 #include <mono/metadata/monitor.h>
62 #include <mono/metadata/debug-mono-symfile.h>
63 #include <mono/utils/mono-memory-model.h>
64 #include <mono/utils/mono-error-internals.h>
65 #include <mono/metadata/mono-basic-block.h>
66 #include <mono/metadata/reflection-internals.h>
67 #include <mono/utils/mono-threads-coop.h>
68
69 #include "trace.h"
70
71 #include "ir-emit.h"
72
73 #include "jit-icalls.h"
74 #include "jit.h"
75 #include "debugger-agent.h"
76 #include "seq-points.h"
77 #include "aot-compiler.h"
78 #include "mini-llvm.h"
79
80 #define BRANCH_COST 10
81 #define INLINE_LENGTH_LIMIT 20
82
83 /* These have 'cfg' as an implicit argument */
84 #define INLINE_FAILURE(msg) do {                                                                        \
85         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
86                 inline_failure (cfg, msg);                                                                              \
87                 goto exception_exit;                                                                                    \
88         } \
89         } while (0)
90 #define CHECK_CFG_EXCEPTION do {\
91                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
92                         goto exception_exit;                                            \
93         } while (0)
94 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
95                 field_access_failure ((cfg), (method), (field));                        \
96                 goto exception_exit;    \
97         } while (0)
98 #define GENERIC_SHARING_FAILURE(opcode) do {            \
99                 if (cfg->gshared) {                                                                     \
100                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
101                         goto exception_exit;    \
102                 }                       \
103         } while (0)
104 #define GSHAREDVT_FAILURE(opcode) do {          \
105         if (cfg->gsharedvt) {                                                                                           \
106                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
107                 goto exception_exit;                                                                                    \
108         }                                                                                                                                       \
109         } while (0)
110 #define OUT_OF_MEMORY_FAILURE do {      \
111                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
112                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
113                 goto exception_exit;    \
114         } while (0)
115 #define DISABLE_AOT(cfg) do { \
116                 if ((cfg)->verbose_level >= 2)                                            \
117                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
118                 (cfg)->disable_aot = TRUE;                                                        \
119         } while (0)
120 #define LOAD_ERROR do { \
121                 break_on_unverified ();                                                         \
122                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
123                 goto exception_exit;                                                                    \
124         } while (0)
125
126 #define TYPE_LOAD_ERROR(klass) do { \
127                 cfg->exception_ptr = klass; \
128                 LOAD_ERROR;                                     \
129         } while (0)
130
131 #define CHECK_CFG_ERROR do {\
132                 if (!mono_error_ok (&cfg->error)) { \
133                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
134                         goto mono_error_exit; \
135                 } \
136         } while (0)
137
138 /* Determine whenever 'ins' represents a load of the 'this' argument */
139 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
140
141 static int ldind_to_load_membase (int opcode);
142 static int stind_to_store_membase (int opcode);
143
144 int mono_op_to_op_imm (int opcode);
145 int mono_op_to_op_imm_noemul (int opcode);
146
147 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
148
149 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
150                                                   guchar *ip, guint real_offset, gboolean inline_always);
151 static MonoInst*
152 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
153
154 inline static MonoInst*
155 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg);
156
157 /* helper methods signatures */
158 static MonoMethodSignature *helper_sig_domain_get;
159 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
160 static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline;
161 static MonoMethodSignature *helper_sig_jit_thread_attach;
162 static MonoMethodSignature *helper_sig_get_tls_tramp;
163 static MonoMethodSignature *helper_sig_set_tls_tramp;
164
165 /* type loading helpers */
166 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, "System.Runtime.CompilerServices", "RuntimeHelpers")
167 static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, "System.Diagnostics", "DebuggableAttribute")
168
169 /*
170  * Instruction metadata
171  */
172 #ifdef MINI_OP
173 #undef MINI_OP
174 #endif
175 #ifdef MINI_OP3
176 #undef MINI_OP3
177 #endif
178 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
179 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
180 #define NONE ' '
181 #define IREG 'i'
182 #define FREG 'f'
183 #define VREG 'v'
184 #define XREG 'x'
185 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
186 #define LREG IREG
187 #else
188 #define LREG 'l'
189 #endif
190 /* keep in sync with the enum in mini.h */
191 const char
192 ins_info[] = {
193 #include "mini-ops.h"
194 };
195 #undef MINI_OP
196 #undef MINI_OP3
197
198 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
199 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
200 /* 
201  * This should contain the index of the last sreg + 1. This is not the same
202  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
203  */
204 const gint8 ins_sreg_counts[] = {
205 #include "mini-ops.h"
206 };
207 #undef MINI_OP
208 #undef MINI_OP3
209
210 guint32
211 mono_alloc_ireg (MonoCompile *cfg)
212 {
213         return alloc_ireg (cfg);
214 }
215
216 guint32
217 mono_alloc_lreg (MonoCompile *cfg)
218 {
219         return alloc_lreg (cfg);
220 }
221
222 guint32
223 mono_alloc_freg (MonoCompile *cfg)
224 {
225         return alloc_freg (cfg);
226 }
227
228 guint32
229 mono_alloc_preg (MonoCompile *cfg)
230 {
231         return alloc_preg (cfg);
232 }
233
234 guint32
235 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
236 {
237         return alloc_dreg (cfg, stack_type);
238 }
239
240 /*
241  * mono_alloc_ireg_ref:
242  *
243  *   Allocate an IREG, and mark it as holding a GC ref.
244  */
245 guint32
246 mono_alloc_ireg_ref (MonoCompile *cfg)
247 {
248         return alloc_ireg_ref (cfg);
249 }
250
251 /*
252  * mono_alloc_ireg_mp:
253  *
254  *   Allocate an IREG, and mark it as holding a managed pointer.
255  */
256 guint32
257 mono_alloc_ireg_mp (MonoCompile *cfg)
258 {
259         return alloc_ireg_mp (cfg);
260 }
261
262 /*
263  * mono_alloc_ireg_copy:
264  *
265  *   Allocate an IREG with the same GC type as VREG.
266  */
267 guint32
268 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
269 {
270         if (vreg_is_ref (cfg, vreg))
271                 return alloc_ireg_ref (cfg);
272         else if (vreg_is_mp (cfg, vreg))
273                 return alloc_ireg_mp (cfg);
274         else
275                 return alloc_ireg (cfg);
276 }
277
278 guint
279 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
280 {
281         if (type->byref)
282                 return OP_MOVE;
283
284         type = mini_get_underlying_type (type);
285 handle_enum:
286         switch (type->type) {
287         case MONO_TYPE_I1:
288         case MONO_TYPE_U1:
289                 return OP_MOVE;
290         case MONO_TYPE_I2:
291         case MONO_TYPE_U2:
292                 return OP_MOVE;
293         case MONO_TYPE_I4:
294         case MONO_TYPE_U4:
295                 return OP_MOVE;
296         case MONO_TYPE_I:
297         case MONO_TYPE_U:
298         case MONO_TYPE_PTR:
299         case MONO_TYPE_FNPTR:
300                 return OP_MOVE;
301         case MONO_TYPE_CLASS:
302         case MONO_TYPE_STRING:
303         case MONO_TYPE_OBJECT:
304         case MONO_TYPE_SZARRAY:
305         case MONO_TYPE_ARRAY:    
306                 return OP_MOVE;
307         case MONO_TYPE_I8:
308         case MONO_TYPE_U8:
309 #if SIZEOF_REGISTER == 8
310                 return OP_MOVE;
311 #else
312                 return OP_LMOVE;
313 #endif
314         case MONO_TYPE_R4:
315                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
316         case MONO_TYPE_R8:
317                 return OP_FMOVE;
318         case MONO_TYPE_VALUETYPE:
319                 if (type->data.klass->enumtype) {
320                         type = mono_class_enum_basetype (type->data.klass);
321                         goto handle_enum;
322                 }
323                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
324                         return OP_XMOVE;
325                 return OP_VMOVE;
326         case MONO_TYPE_TYPEDBYREF:
327                 return OP_VMOVE;
328         case MONO_TYPE_GENERICINST:
329                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
330                         return OP_XMOVE;
331                 type = &type->data.generic_class->container_class->byval_arg;
332                 goto handle_enum;
333         case MONO_TYPE_VAR:
334         case MONO_TYPE_MVAR:
335                 g_assert (cfg->gshared);
336                 if (mini_type_var_is_vt (type))
337                         return OP_VMOVE;
338                 else
339                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
340         default:
341                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
342         }
343         return -1;
344 }
345
346 void
347 mono_print_bb (MonoBasicBlock *bb, const char *msg)
348 {
349         int i;
350         MonoInst *tree;
351         GString *str = g_string_new ("");
352
353         g_string_append_printf (str, "%s %d: [IN: ", msg, bb->block_num);
354         for (i = 0; i < bb->in_count; ++i)
355                 g_string_append_printf (str, " BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
356         g_string_append_printf (str, ", OUT: ");
357         for (i = 0; i < bb->out_count; ++i)
358                 g_string_append_printf (str, " BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
359         g_string_append_printf (str, " ]\n");
360
361         g_print ("%s", str->str);
362         g_string_free (str, TRUE);
363
364         for (tree = bb->code; tree; tree = tree->next)
365                 mono_print_ins_index (-1, tree);
366 }
367
368 void
369 mono_create_helper_signatures (void)
370 {
371         helper_sig_domain_get = mono_create_icall_signature ("ptr");
372         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
373         helper_sig_llvmonly_imt_trampoline = mono_create_icall_signature ("ptr ptr ptr");
374         helper_sig_jit_thread_attach = mono_create_icall_signature ("ptr ptr");
375         helper_sig_get_tls_tramp = mono_create_icall_signature ("ptr");
376         helper_sig_set_tls_tramp = mono_create_icall_signature ("void ptr");
377 }
378
379 static MONO_NEVER_INLINE void
380 break_on_unverified (void)
381 {
382         if (mini_get_debug_options ()->break_on_unverified)
383                 G_BREAKPOINT ();
384 }
385
386 static MONO_NEVER_INLINE void
387 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
388 {
389         char *method_fname = mono_method_full_name (method, TRUE);
390         char *field_fname = mono_field_full_name (field);
391         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
392         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
393         g_free (method_fname);
394         g_free (field_fname);
395 }
396
397 static MONO_NEVER_INLINE void
398 inline_failure (MonoCompile *cfg, const char *msg)
399 {
400         if (cfg->verbose_level >= 2)
401                 printf ("inline failed: %s\n", msg);
402         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
403 }
404
405 static MONO_NEVER_INLINE void
406 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
407 {
408         if (cfg->verbose_level > 2)                                                                                     \
409                 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);
410         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
411 }
412
413 static MONO_NEVER_INLINE void
414 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
415 {
416         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);
417         if (cfg->verbose_level >= 2)
418                 printf ("%s\n", cfg->exception_message);
419         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
420 }
421
422 /*
423  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
424  * foo<T> (int i) { ldarg.0; box T; }
425  */
426 #define UNVERIFIED do { \
427         if (cfg->gsharedvt) { \
428                 if (cfg->verbose_level > 2)                                                                     \
429                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
430                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
431                 goto exception_exit;                                                                                    \
432         }                                                                                                                                       \
433         break_on_unverified ();                                                                                         \
434         goto unverified;                                                                                                        \
435 } while (0)
436
437 #define GET_BBLOCK(cfg,tblock,ip) do {  \
438                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
439                 if (!(tblock)) {        \
440                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
441             NEW_BBLOCK (cfg, (tblock)); \
442                         (tblock)->cil_code = (ip);      \
443                         ADD_BBLOCK (cfg, (tblock));     \
444                 } \
445         } while (0)
446
447 #if defined(TARGET_X86) || defined(TARGET_AMD64)
448 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
449                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
450                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
451                 (dest)->sreg1 = (sr1); \
452                 (dest)->sreg2 = (sr2); \
453                 (dest)->inst_imm = (imm); \
454                 (dest)->backend.shift_amount = (shift); \
455                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
456         } while (0)
457 #endif
458
459 /* Emit conversions so both operands of a binary opcode are of the same type */
460 static void
461 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
462 {
463         MonoInst *arg1 = *arg1_ref;
464         MonoInst *arg2 = *arg2_ref;
465
466         if (cfg->r4fp &&
467                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
468                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
469                 MonoInst *conv;
470
471                 /* Mixing r4/r8 is allowed by the spec */
472                 if (arg1->type == STACK_R4) {
473                         int dreg = alloc_freg (cfg);
474
475                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
476                         conv->type = STACK_R8;
477                         ins->sreg1 = dreg;
478                         *arg1_ref = conv;
479                 }
480                 if (arg2->type == STACK_R4) {
481                         int dreg = alloc_freg (cfg);
482
483                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
484                         conv->type = STACK_R8;
485                         ins->sreg2 = dreg;
486                         *arg2_ref = conv;
487                 }
488         }
489
490 #if SIZEOF_REGISTER == 8
491         /* FIXME: Need to add many more cases */
492         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
493                 MonoInst *widen;
494
495                 int dr = alloc_preg (cfg);
496                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
497                 (ins)->sreg2 = widen->dreg;
498         }
499 #endif
500 }
501
502 #define ADD_BINOP(op) do {      \
503                 MONO_INST_NEW (cfg, ins, (op)); \
504                 sp -= 2;        \
505                 ins->sreg1 = sp [0]->dreg;      \
506                 ins->sreg2 = sp [1]->dreg;      \
507                 type_from_op (cfg, ins, sp [0], sp [1]);        \
508                 CHECK_TYPE (ins);       \
509                 /* Have to insert a widening op */               \
510         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
511         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
512         MONO_ADD_INS ((cfg)->cbb, (ins)); \
513         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
514         } while (0)
515
516 #define ADD_UNOP(op) do {       \
517                 MONO_INST_NEW (cfg, ins, (op)); \
518                 sp--;   \
519                 ins->sreg1 = sp [0]->dreg;      \
520                 type_from_op (cfg, ins, sp [0], NULL);  \
521                 CHECK_TYPE (ins);       \
522         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
523         MONO_ADD_INS ((cfg)->cbb, (ins)); \
524                 *sp++ = mono_decompose_opcode (cfg, ins);       \
525         } while (0)
526
527 #define ADD_BINCOND(next_block) do {    \
528                 MonoInst *cmp;  \
529                 sp -= 2; \
530                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
531                 cmp->sreg1 = sp [0]->dreg;      \
532                 cmp->sreg2 = sp [1]->dreg;      \
533                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
534                 CHECK_TYPE (cmp);       \
535                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
536                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
537                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
538                 GET_BBLOCK (cfg, tblock, target);               \
539                 link_bblock (cfg, cfg->cbb, tblock);    \
540                 ins->inst_true_bb = tblock;     \
541                 if ((next_block)) {     \
542                         link_bblock (cfg, cfg->cbb, (next_block));      \
543                         ins->inst_false_bb = (next_block);      \
544                         start_new_bblock = 1;   \
545                 } else {        \
546                         GET_BBLOCK (cfg, tblock, ip);           \
547                         link_bblock (cfg, cfg->cbb, tblock);    \
548                         ins->inst_false_bb = tblock;    \
549                         start_new_bblock = 2;   \
550                 }       \
551                 if (sp != stack_start) {                                                                        \
552                     handle_stack_args (cfg, stack_start, sp - stack_start); \
553                         CHECK_UNVERIFIABLE (cfg); \
554                 } \
555         MONO_ADD_INS (cfg->cbb, cmp); \
556                 MONO_ADD_INS (cfg->cbb, ins);   \
557         } while (0)
558
559 /* *
560  * link_bblock: Links two basic blocks
561  *
562  * links two basic blocks in the control flow graph, the 'from'
563  * argument is the starting block and the 'to' argument is the block
564  * the control flow ends to after 'from'.
565  */
566 static void
567 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
568 {
569         MonoBasicBlock **newa;
570         int i, found;
571
572 #if 0
573         if (from->cil_code) {
574                 if (to->cil_code)
575                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
576                 else
577                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
578         } else {
579                 if (to->cil_code)
580                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
581                 else
582                         printf ("edge from entry to exit\n");
583         }
584 #endif
585
586         found = FALSE;
587         for (i = 0; i < from->out_count; ++i) {
588                 if (to == from->out_bb [i]) {
589                         found = TRUE;
590                         break;
591                 }
592         }
593         if (!found) {
594                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
595                 for (i = 0; i < from->out_count; ++i) {
596                         newa [i] = from->out_bb [i];
597                 }
598                 newa [i] = to;
599                 from->out_count++;
600                 from->out_bb = newa;
601         }
602
603         found = FALSE;
604         for (i = 0; i < to->in_count; ++i) {
605                 if (from == to->in_bb [i]) {
606                         found = TRUE;
607                         break;
608                 }
609         }
610         if (!found) {
611                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
612                 for (i = 0; i < to->in_count; ++i) {
613                         newa [i] = to->in_bb [i];
614                 }
615                 newa [i] = from;
616                 to->in_count++;
617                 to->in_bb = newa;
618         }
619 }
620
621 void
622 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
623 {
624         link_bblock (cfg, from, to);
625 }
626
627 /**
628  * mono_find_block_region:
629  *
630  *   We mark each basic block with a region ID. We use that to avoid BB
631  *   optimizations when blocks are in different regions.
632  *
633  * Returns:
634  *   A region token that encodes where this region is, and information
635  *   about the clause owner for this block.
636  *
637  *   The region encodes the try/catch/filter clause that owns this block
638  *   as well as the type.  -1 is a special value that represents a block
639  *   that is in none of try/catch/filter.
640  */
641 static int
642 mono_find_block_region (MonoCompile *cfg, int offset)
643 {
644         MonoMethodHeader *header = cfg->header;
645         MonoExceptionClause *clause;
646         int i;
647
648         for (i = 0; i < header->num_clauses; ++i) {
649                 clause = &header->clauses [i];
650                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
651                     (offset < (clause->handler_offset)))
652                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
653                            
654                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
655                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
656                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
657                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
658                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
659                         else
660                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
661                 }
662         }
663         for (i = 0; i < header->num_clauses; ++i) {
664                 clause = &header->clauses [i];
665
666                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
667                         return ((i + 1) << 8) | clause->flags;
668         }
669
670         return -1;
671 }
672
673 static gboolean
674 ip_in_finally_clause (MonoCompile *cfg, int offset)
675 {
676         MonoMethodHeader *header = cfg->header;
677         MonoExceptionClause *clause;
678         int i;
679
680         for (i = 0; i < header->num_clauses; ++i) {
681                 clause = &header->clauses [i];
682                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
683                         continue;
684
685                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
686                         return TRUE;
687         }
688         return FALSE;
689 }
690
691 static GList*
692 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
693 {
694         MonoMethodHeader *header = cfg->header;
695         MonoExceptionClause *clause;
696         int i;
697         GList *res = NULL;
698
699         for (i = 0; i < header->num_clauses; ++i) {
700                 clause = &header->clauses [i];
701                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
702                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
703                         if (clause->flags == type)
704                                 res = g_list_append (res, clause);
705                 }
706         }
707         return res;
708 }
709
710 static void
711 mono_create_spvar_for_region (MonoCompile *cfg, int region)
712 {
713         MonoInst *var;
714
715         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
716         if (var)
717                 return;
718
719         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
720         /* prevent it from being register allocated */
721         var->flags |= MONO_INST_VOLATILE;
722
723         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
724 }
725
726 MonoInst *
727 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
728 {
729         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
730 }
731
732 static MonoInst*
733 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
734 {
735         MonoInst *var;
736
737         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
738         if (var)
739                 return var;
740
741         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
742         /* prevent it from being register allocated */
743         var->flags |= MONO_INST_VOLATILE;
744
745         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
746
747         return var;
748 }
749
750 /*
751  * Returns the type used in the eval stack when @type is loaded.
752  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
753  */
754 void
755 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
756 {
757         MonoClass *klass;
758
759         type = mini_get_underlying_type (type);
760         inst->klass = klass = mono_class_from_mono_type (type);
761         if (type->byref) {
762                 inst->type = STACK_MP;
763                 return;
764         }
765
766 handle_enum:
767         switch (type->type) {
768         case MONO_TYPE_VOID:
769                 inst->type = STACK_INV;
770                 return;
771         case MONO_TYPE_I1:
772         case MONO_TYPE_U1:
773         case MONO_TYPE_I2:
774         case MONO_TYPE_U2:
775         case MONO_TYPE_I4:
776         case MONO_TYPE_U4:
777                 inst->type = STACK_I4;
778                 return;
779         case MONO_TYPE_I:
780         case MONO_TYPE_U:
781         case MONO_TYPE_PTR:
782         case MONO_TYPE_FNPTR:
783                 inst->type = STACK_PTR;
784                 return;
785         case MONO_TYPE_CLASS:
786         case MONO_TYPE_STRING:
787         case MONO_TYPE_OBJECT:
788         case MONO_TYPE_SZARRAY:
789         case MONO_TYPE_ARRAY:    
790                 inst->type = STACK_OBJ;
791                 return;
792         case MONO_TYPE_I8:
793         case MONO_TYPE_U8:
794                 inst->type = STACK_I8;
795                 return;
796         case MONO_TYPE_R4:
797                 inst->type = cfg->r4_stack_type;
798                 break;
799         case MONO_TYPE_R8:
800                 inst->type = STACK_R8;
801                 return;
802         case MONO_TYPE_VALUETYPE:
803                 if (type->data.klass->enumtype) {
804                         type = mono_class_enum_basetype (type->data.klass);
805                         goto handle_enum;
806                 } else {
807                         inst->klass = klass;
808                         inst->type = STACK_VTYPE;
809                         return;
810                 }
811         case MONO_TYPE_TYPEDBYREF:
812                 inst->klass = mono_defaults.typed_reference_class;
813                 inst->type = STACK_VTYPE;
814                 return;
815         case MONO_TYPE_GENERICINST:
816                 type = &type->data.generic_class->container_class->byval_arg;
817                 goto handle_enum;
818         case MONO_TYPE_VAR:
819         case MONO_TYPE_MVAR:
820                 g_assert (cfg->gshared);
821                 if (mini_is_gsharedvt_type (type)) {
822                         g_assert (cfg->gsharedvt);
823                         inst->type = STACK_VTYPE;
824                 } else {
825                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
826                 }
827                 return;
828         default:
829                 g_error ("unknown type 0x%02x in eval stack type", type->type);
830         }
831 }
832
833 /*
834  * The following tables are used to quickly validate the IL code in type_from_op ().
835  */
836 static const char
837 bin_num_table [STACK_MAX] [STACK_MAX] = {
838         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
839         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
840         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
841         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
842         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
843         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
844         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
845         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
846         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
847 };
848
849 static const char 
850 neg_table [] = {
851         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
852 };
853
854 /* reduce the size of this table */
855 static const char
856 bin_int_table [STACK_MAX] [STACK_MAX] = {
857         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
858         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
859         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
860         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
861         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
862         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
863         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
864         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
865 };
866
867 static const char
868 bin_comp_table [STACK_MAX] [STACK_MAX] = {
869 /*      Inv i  L  p  F  &  O  vt r4 */
870         {0},
871         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
872         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
873         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
874         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
875         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
876         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
877         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
878         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
879 };
880
881 /* reduce the size of this table */
882 static const char
883 shift_table [STACK_MAX] [STACK_MAX] = {
884         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
885         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
886         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
887         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
888         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
889         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
890         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
891         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
892 };
893
894 /*
895  * Tables to map from the non-specific opcode to the matching
896  * type-specific opcode.
897  */
898 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
899 static const guint16
900 binops_op_map [STACK_MAX] = {
901         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
902 };
903
904 /* handles from CEE_NEG to CEE_CONV_U8 */
905 static const guint16
906 unops_op_map [STACK_MAX] = {
907         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
908 };
909
910 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
911 static const guint16
912 ovfops_op_map [STACK_MAX] = {
913         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
914 };
915
916 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
917 static const guint16
918 ovf2ops_op_map [STACK_MAX] = {
919         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
920 };
921
922 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
923 static const guint16
924 ovf3ops_op_map [STACK_MAX] = {
925         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
926 };
927
928 /* handles from CEE_BEQ to CEE_BLT_UN */
929 static const guint16
930 beqops_op_map [STACK_MAX] = {
931         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
932 };
933
934 /* handles from CEE_CEQ to CEE_CLT_UN */
935 static const guint16
936 ceqops_op_map [STACK_MAX] = {
937         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
938 };
939
940 /*
941  * Sets ins->type (the type on the eval stack) according to the
942  * type of the opcode and the arguments to it.
943  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
944  *
945  * FIXME: this function sets ins->type unconditionally in some cases, but
946  * it should set it to invalid for some types (a conv.x on an object)
947  */
948 static void
949 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
950 {
951         switch (ins->opcode) {
952         /* binops */
953         case CEE_ADD:
954         case CEE_SUB:
955         case CEE_MUL:
956         case CEE_DIV:
957         case CEE_REM:
958                 /* FIXME: check unverifiable args for STACK_MP */
959                 ins->type = bin_num_table [src1->type] [src2->type];
960                 ins->opcode += binops_op_map [ins->type];
961                 break;
962         case CEE_DIV_UN:
963         case CEE_REM_UN:
964         case CEE_AND:
965         case CEE_OR:
966         case CEE_XOR:
967                 ins->type = bin_int_table [src1->type] [src2->type];
968                 ins->opcode += binops_op_map [ins->type];
969                 break;
970         case CEE_SHL:
971         case CEE_SHR:
972         case CEE_SHR_UN:
973                 ins->type = shift_table [src1->type] [src2->type];
974                 ins->opcode += binops_op_map [ins->type];
975                 break;
976         case OP_COMPARE:
977         case OP_LCOMPARE:
978         case OP_ICOMPARE:
979                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
980                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
981                         ins->opcode = OP_LCOMPARE;
982                 else if (src1->type == STACK_R4)
983                         ins->opcode = OP_RCOMPARE;
984                 else if (src1->type == STACK_R8)
985                         ins->opcode = OP_FCOMPARE;
986                 else
987                         ins->opcode = OP_ICOMPARE;
988                 break;
989         case OP_ICOMPARE_IMM:
990                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
991                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
992                         ins->opcode = OP_LCOMPARE_IMM;          
993                 break;
994         case CEE_BEQ:
995         case CEE_BGE:
996         case CEE_BGT:
997         case CEE_BLE:
998         case CEE_BLT:
999         case CEE_BNE_UN:
1000         case CEE_BGE_UN:
1001         case CEE_BGT_UN:
1002         case CEE_BLE_UN:
1003         case CEE_BLT_UN:
1004                 ins->opcode += beqops_op_map [src1->type];
1005                 break;
1006         case OP_CEQ:
1007                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
1008                 ins->opcode += ceqops_op_map [src1->type];
1009                 break;
1010         case OP_CGT:
1011         case OP_CGT_UN:
1012         case OP_CLT:
1013         case OP_CLT_UN:
1014                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
1015                 ins->opcode += ceqops_op_map [src1->type];
1016                 break;
1017         /* unops */
1018         case CEE_NEG:
1019                 ins->type = neg_table [src1->type];
1020                 ins->opcode += unops_op_map [ins->type];
1021                 break;
1022         case CEE_NOT:
1023                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1024                         ins->type = src1->type;
1025                 else
1026                         ins->type = STACK_INV;
1027                 ins->opcode += unops_op_map [ins->type];
1028                 break;
1029         case CEE_CONV_I1:
1030         case CEE_CONV_I2:
1031         case CEE_CONV_I4:
1032         case CEE_CONV_U4:
1033                 ins->type = STACK_I4;
1034                 ins->opcode += unops_op_map [src1->type];
1035                 break;
1036         case CEE_CONV_R_UN:
1037                 ins->type = STACK_R8;
1038                 switch (src1->type) {
1039                 case STACK_I4:
1040                 case STACK_PTR:
1041                         ins->opcode = OP_ICONV_TO_R_UN;
1042                         break;
1043                 case STACK_I8:
1044                         ins->opcode = OP_LCONV_TO_R_UN; 
1045                         break;
1046                 }
1047                 break;
1048         case CEE_CONV_OVF_I1:
1049         case CEE_CONV_OVF_U1:
1050         case CEE_CONV_OVF_I2:
1051         case CEE_CONV_OVF_U2:
1052         case CEE_CONV_OVF_I4:
1053         case CEE_CONV_OVF_U4:
1054                 ins->type = STACK_I4;
1055                 ins->opcode += ovf3ops_op_map [src1->type];
1056                 break;
1057         case CEE_CONV_OVF_I_UN:
1058         case CEE_CONV_OVF_U_UN:
1059                 ins->type = STACK_PTR;
1060                 ins->opcode += ovf2ops_op_map [src1->type];
1061                 break;
1062         case CEE_CONV_OVF_I1_UN:
1063         case CEE_CONV_OVF_I2_UN:
1064         case CEE_CONV_OVF_I4_UN:
1065         case CEE_CONV_OVF_U1_UN:
1066         case CEE_CONV_OVF_U2_UN:
1067         case CEE_CONV_OVF_U4_UN:
1068                 ins->type = STACK_I4;
1069                 ins->opcode += ovf2ops_op_map [src1->type];
1070                 break;
1071         case CEE_CONV_U:
1072                 ins->type = STACK_PTR;
1073                 switch (src1->type) {
1074                 case STACK_I4:
1075                         ins->opcode = OP_ICONV_TO_U;
1076                         break;
1077                 case STACK_PTR:
1078                 case STACK_MP:
1079 #if SIZEOF_VOID_P == 8
1080                         ins->opcode = OP_LCONV_TO_U;
1081 #else
1082                         ins->opcode = OP_MOVE;
1083 #endif
1084                         break;
1085                 case STACK_I8:
1086                         ins->opcode = OP_LCONV_TO_U;
1087                         break;
1088                 case STACK_R8:
1089                         ins->opcode = OP_FCONV_TO_U;
1090                         break;
1091                 }
1092                 break;
1093         case CEE_CONV_I8:
1094         case CEE_CONV_U8:
1095                 ins->type = STACK_I8;
1096                 ins->opcode += unops_op_map [src1->type];
1097                 break;
1098         case CEE_CONV_OVF_I8:
1099         case CEE_CONV_OVF_U8:
1100                 ins->type = STACK_I8;
1101                 ins->opcode += ovf3ops_op_map [src1->type];
1102                 break;
1103         case CEE_CONV_OVF_U8_UN:
1104         case CEE_CONV_OVF_I8_UN:
1105                 ins->type = STACK_I8;
1106                 ins->opcode += ovf2ops_op_map [src1->type];
1107                 break;
1108         case CEE_CONV_R4:
1109                 ins->type = cfg->r4_stack_type;
1110                 ins->opcode += unops_op_map [src1->type];
1111                 break;
1112         case CEE_CONV_R8:
1113                 ins->type = STACK_R8;
1114                 ins->opcode += unops_op_map [src1->type];
1115                 break;
1116         case OP_CKFINITE:
1117                 ins->type = STACK_R8;           
1118                 break;
1119         case CEE_CONV_U2:
1120         case CEE_CONV_U1:
1121                 ins->type = STACK_I4;
1122                 ins->opcode += ovfops_op_map [src1->type];
1123                 break;
1124         case CEE_CONV_I:
1125         case CEE_CONV_OVF_I:
1126         case CEE_CONV_OVF_U:
1127                 ins->type = STACK_PTR;
1128                 ins->opcode += ovfops_op_map [src1->type];
1129                 break;
1130         case CEE_ADD_OVF:
1131         case CEE_ADD_OVF_UN:
1132         case CEE_MUL_OVF:
1133         case CEE_MUL_OVF_UN:
1134         case CEE_SUB_OVF:
1135         case CEE_SUB_OVF_UN:
1136                 ins->type = bin_num_table [src1->type] [src2->type];
1137                 ins->opcode += ovfops_op_map [src1->type];
1138                 if (ins->type == STACK_R8)
1139                         ins->type = STACK_INV;
1140                 break;
1141         case OP_LOAD_MEMBASE:
1142                 ins->type = STACK_PTR;
1143                 break;
1144         case OP_LOADI1_MEMBASE:
1145         case OP_LOADU1_MEMBASE:
1146         case OP_LOADI2_MEMBASE:
1147         case OP_LOADU2_MEMBASE:
1148         case OP_LOADI4_MEMBASE:
1149         case OP_LOADU4_MEMBASE:
1150                 ins->type = STACK_PTR;
1151                 break;
1152         case OP_LOADI8_MEMBASE:
1153                 ins->type = STACK_I8;
1154                 break;
1155         case OP_LOADR4_MEMBASE:
1156                 ins->type = cfg->r4_stack_type;
1157                 break;
1158         case OP_LOADR8_MEMBASE:
1159                 ins->type = STACK_R8;
1160                 break;
1161         default:
1162                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1163                 break;
1164         }
1165
1166         if (ins->type == STACK_MP)
1167                 ins->klass = mono_defaults.object_class;
1168 }
1169
1170 static const char 
1171 ldind_type [] = {
1172         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1173 };
1174
1175 #if 0
1176
1177 static const char
1178 param_table [STACK_MAX] [STACK_MAX] = {
1179         {0},
1180 };
1181
1182 static int
1183 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1184 {
1185         int i;
1186
1187         if (sig->hasthis) {
1188                 switch (args->type) {
1189                 case STACK_I4:
1190                 case STACK_I8:
1191                 case STACK_R8:
1192                 case STACK_VTYPE:
1193                 case STACK_INV:
1194                         return 0;
1195                 }
1196                 args++;
1197         }
1198         for (i = 0; i < sig->param_count; ++i) {
1199                 switch (args [i].type) {
1200                 case STACK_INV:
1201                         return 0;
1202                 case STACK_MP:
1203                         if (!sig->params [i]->byref)
1204                                 return 0;
1205                         continue;
1206                 case STACK_OBJ:
1207                         if (sig->params [i]->byref)
1208                                 return 0;
1209                         switch (sig->params [i]->type) {
1210                         case MONO_TYPE_CLASS:
1211                         case MONO_TYPE_STRING:
1212                         case MONO_TYPE_OBJECT:
1213                         case MONO_TYPE_SZARRAY:
1214                         case MONO_TYPE_ARRAY:
1215                                 break;
1216                         default:
1217                                 return 0;
1218                         }
1219                         continue;
1220                 case STACK_R8:
1221                         if (sig->params [i]->byref)
1222                                 return 0;
1223                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1224                                 return 0;
1225                         continue;
1226                 case STACK_PTR:
1227                 case STACK_I4:
1228                 case STACK_I8:
1229                 case STACK_VTYPE:
1230                         break;
1231                 }
1232                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1233                         return 0;*/
1234         }
1235         return 1;
1236 }
1237 #endif
1238
1239 /*
1240  * When we need a pointer to the current domain many times in a method, we
1241  * call mono_domain_get() once and we store the result in a local variable.
1242  * This function returns the variable that represents the MonoDomain*.
1243  */
1244 inline static MonoInst *
1245 mono_get_domainvar (MonoCompile *cfg)
1246 {
1247         if (!cfg->domainvar)
1248                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1249         return cfg->domainvar;
1250 }
1251
1252 /*
1253  * The got_var contains the address of the Global Offset Table when AOT 
1254  * compiling.
1255  */
1256 MonoInst *
1257 mono_get_got_var (MonoCompile *cfg)
1258 {
1259         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1260                 return NULL;
1261         if (!cfg->got_var) {
1262                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1263         }
1264         return cfg->got_var;
1265 }
1266
1267 static MonoInst *
1268 mono_get_vtable_var (MonoCompile *cfg)
1269 {
1270         g_assert (cfg->gshared);
1271
1272         if (!cfg->rgctx_var) {
1273                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1274                 /* force the var to be stack allocated */
1275                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1276         }
1277
1278         return cfg->rgctx_var;
1279 }
1280
1281 static MonoType*
1282 type_from_stack_type (MonoInst *ins) {
1283         switch (ins->type) {
1284         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1285         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1286         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1287         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1288         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1289         case STACK_MP:
1290                 return &ins->klass->this_arg;
1291         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1292         case STACK_VTYPE: return &ins->klass->byval_arg;
1293         default:
1294                 g_error ("stack type %d to monotype not handled\n", ins->type);
1295         }
1296         return NULL;
1297 }
1298
1299 static G_GNUC_UNUSED int
1300 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1301 {
1302         t = mono_type_get_underlying_type (t);
1303         switch (t->type) {
1304         case MONO_TYPE_I1:
1305         case MONO_TYPE_U1:
1306         case MONO_TYPE_I2:
1307         case MONO_TYPE_U2:
1308         case MONO_TYPE_I4:
1309         case MONO_TYPE_U4:
1310                 return STACK_I4;
1311         case MONO_TYPE_I:
1312         case MONO_TYPE_U:
1313         case MONO_TYPE_PTR:
1314         case MONO_TYPE_FNPTR:
1315                 return STACK_PTR;
1316         case MONO_TYPE_CLASS:
1317         case MONO_TYPE_STRING:
1318         case MONO_TYPE_OBJECT:
1319         case MONO_TYPE_SZARRAY:
1320         case MONO_TYPE_ARRAY:    
1321                 return STACK_OBJ;
1322         case MONO_TYPE_I8:
1323         case MONO_TYPE_U8:
1324                 return STACK_I8;
1325         case MONO_TYPE_R4:
1326                 return cfg->r4_stack_type;
1327         case MONO_TYPE_R8:
1328                 return STACK_R8;
1329         case MONO_TYPE_VALUETYPE:
1330         case MONO_TYPE_TYPEDBYREF:
1331                 return STACK_VTYPE;
1332         case MONO_TYPE_GENERICINST:
1333                 if (mono_type_generic_inst_is_valuetype (t))
1334                         return STACK_VTYPE;
1335                 else
1336                         return STACK_OBJ;
1337                 break;
1338         default:
1339                 g_assert_not_reached ();
1340         }
1341
1342         return -1;
1343 }
1344
1345 static MonoClass*
1346 array_access_to_klass (int opcode)
1347 {
1348         switch (opcode) {
1349         case CEE_LDELEM_U1:
1350                 return mono_defaults.byte_class;
1351         case CEE_LDELEM_U2:
1352                 return mono_defaults.uint16_class;
1353         case CEE_LDELEM_I:
1354         case CEE_STELEM_I:
1355                 return mono_defaults.int_class;
1356         case CEE_LDELEM_I1:
1357         case CEE_STELEM_I1:
1358                 return mono_defaults.sbyte_class;
1359         case CEE_LDELEM_I2:
1360         case CEE_STELEM_I2:
1361                 return mono_defaults.int16_class;
1362         case CEE_LDELEM_I4:
1363         case CEE_STELEM_I4:
1364                 return mono_defaults.int32_class;
1365         case CEE_LDELEM_U4:
1366                 return mono_defaults.uint32_class;
1367         case CEE_LDELEM_I8:
1368         case CEE_STELEM_I8:
1369                 return mono_defaults.int64_class;
1370         case CEE_LDELEM_R4:
1371         case CEE_STELEM_R4:
1372                 return mono_defaults.single_class;
1373         case CEE_LDELEM_R8:
1374         case CEE_STELEM_R8:
1375                 return mono_defaults.double_class;
1376         case CEE_LDELEM_REF:
1377         case CEE_STELEM_REF:
1378                 return mono_defaults.object_class;
1379         default:
1380                 g_assert_not_reached ();
1381         }
1382         return NULL;
1383 }
1384
1385 /*
1386  * We try to share variables when possible
1387  */
1388 static MonoInst *
1389 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1390 {
1391         MonoInst *res;
1392         int pos, vnum;
1393
1394         /* inlining can result in deeper stacks */ 
1395         if (slot >= cfg->header->max_stack)
1396                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1397
1398         pos = ins->type - 1 + slot * STACK_MAX;
1399
1400         switch (ins->type) {
1401         case STACK_I4:
1402         case STACK_I8:
1403         case STACK_R8:
1404         case STACK_PTR:
1405         case STACK_MP:
1406         case STACK_OBJ:
1407                 if ((vnum = cfg->intvars [pos]))
1408                         return cfg->varinfo [vnum];
1409                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1410                 cfg->intvars [pos] = res->inst_c0;
1411                 break;
1412         default:
1413                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1414         }
1415         return res;
1416 }
1417
1418 static void
1419 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1420 {
1421         /* 
1422          * Don't use this if a generic_context is set, since that means AOT can't
1423          * look up the method using just the image+token.
1424          * table == 0 means this is a reference made from a wrapper.
1425          */
1426         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1427                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1428                 jump_info_token->image = image;
1429                 jump_info_token->token = token;
1430                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1431         }
1432 }
1433
1434 /*
1435  * This function is called to handle items that are left on the evaluation stack
1436  * at basic block boundaries. What happens is that we save the values to local variables
1437  * and we reload them later when first entering the target basic block (with the
1438  * handle_loaded_temps () function).
1439  * A single joint point will use the same variables (stored in the array bb->out_stack or
1440  * bb->in_stack, if the basic block is before or after the joint point).
1441  *
1442  * This function needs to be called _before_ emitting the last instruction of
1443  * the bb (i.e. before emitting a branch).
1444  * If the stack merge fails at a join point, cfg->unverifiable is set.
1445  */
1446 static void
1447 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1448 {
1449         int i, bindex;
1450         MonoBasicBlock *bb = cfg->cbb;
1451         MonoBasicBlock *outb;
1452         MonoInst *inst, **locals;
1453         gboolean found;
1454
1455         if (!count)
1456                 return;
1457         if (cfg->verbose_level > 3)
1458                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1459         if (!bb->out_scount) {
1460                 bb->out_scount = count;
1461                 //printf ("bblock %d has out:", bb->block_num);
1462                 found = FALSE;
1463                 for (i = 0; i < bb->out_count; ++i) {
1464                         outb = bb->out_bb [i];
1465                         /* exception handlers are linked, but they should not be considered for stack args */
1466                         if (outb->flags & BB_EXCEPTION_HANDLER)
1467                                 continue;
1468                         //printf (" %d", outb->block_num);
1469                         if (outb->in_stack) {
1470                                 found = TRUE;
1471                                 bb->out_stack = outb->in_stack;
1472                                 break;
1473                         }
1474                 }
1475                 //printf ("\n");
1476                 if (!found) {
1477                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1478                         for (i = 0; i < count; ++i) {
1479                                 /* 
1480                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1481                                  * stack slot and if they are of the same type.
1482                                  * This won't cause conflicts since if 'local' is used to 
1483                                  * store one of the values in the in_stack of a bblock, then
1484                                  * the same variable will be used for the same outgoing stack 
1485                                  * slot as well. 
1486                                  * This doesn't work when inlining methods, since the bblocks
1487                                  * in the inlined methods do not inherit their in_stack from
1488                                  * the bblock they are inlined to. See bug #58863 for an
1489                                  * example.
1490                                  */
1491                                 if (cfg->inlined_method)
1492                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1493                                 else
1494                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1495                         }
1496                 }
1497         }
1498
1499         for (i = 0; i < bb->out_count; ++i) {
1500                 outb = bb->out_bb [i];
1501                 /* exception handlers are linked, but they should not be considered for stack args */
1502                 if (outb->flags & BB_EXCEPTION_HANDLER)
1503                         continue;
1504                 if (outb->in_scount) {
1505                         if (outb->in_scount != bb->out_scount) {
1506                                 cfg->unverifiable = TRUE;
1507                                 return;
1508                         }
1509                         continue; /* check they are the same locals */
1510                 }
1511                 outb->in_scount = count;
1512                 outb->in_stack = bb->out_stack;
1513         }
1514
1515         locals = bb->out_stack;
1516         cfg->cbb = bb;
1517         for (i = 0; i < count; ++i) {
1518                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1519                 inst->cil_code = sp [i]->cil_code;
1520                 sp [i] = locals [i];
1521                 if (cfg->verbose_level > 3)
1522                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1523         }
1524
1525         /*
1526          * It is possible that the out bblocks already have in_stack assigned, and
1527          * the in_stacks differ. In this case, we will store to all the different 
1528          * in_stacks.
1529          */
1530
1531         found = TRUE;
1532         bindex = 0;
1533         while (found) {
1534                 /* Find a bblock which has a different in_stack */
1535                 found = FALSE;
1536                 while (bindex < bb->out_count) {
1537                         outb = bb->out_bb [bindex];
1538                         /* exception handlers are linked, but they should not be considered for stack args */
1539                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1540                                 bindex++;
1541                                 continue;
1542                         }
1543                         if (outb->in_stack != locals) {
1544                                 for (i = 0; i < count; ++i) {
1545                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1546                                         inst->cil_code = sp [i]->cil_code;
1547                                         sp [i] = locals [i];
1548                                         if (cfg->verbose_level > 3)
1549                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1550                                 }
1551                                 locals = outb->in_stack;
1552                                 found = TRUE;
1553                                 break;
1554                         }
1555                         bindex ++;
1556                 }
1557         }
1558 }
1559
1560 static MonoInst*
1561 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1562 {
1563         MonoInst *ins;
1564
1565         if (cfg->compile_aot) {
1566                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1567         } else {
1568                 MonoJumpInfo ji;
1569                 gpointer target;
1570                 MonoError error;
1571
1572                 ji.type = patch_type;
1573                 ji.data.target = data;
1574                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1575                 mono_error_assert_ok (&error);
1576
1577                 EMIT_NEW_PCONST (cfg, ins, target);
1578         }
1579         return ins;
1580 }
1581
1582 MonoInst*
1583 mini_emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1584 {
1585         return emit_runtime_constant (cfg, patch_type, data);
1586 }
1587
1588 static void 
1589 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1590 {
1591         int val_reg;
1592
1593         g_assert (val == 0);
1594
1595         if (align == 0)
1596                 align = 4;
1597
1598         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1599                 switch (size) {
1600                 case 1:
1601                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1602                         return;
1603                 case 2:
1604                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1605                         return;
1606                 case 4:
1607                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1608                         return;
1609 #if SIZEOF_REGISTER == 8
1610                 case 8:
1611                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1612                         return;
1613 #endif
1614                 }
1615         }
1616
1617         val_reg = alloc_preg (cfg);
1618
1619         if (SIZEOF_REGISTER == 8)
1620                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1621         else
1622                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1623
1624         if (align < 4) {
1625                 /* This could be optimized further if neccesary */
1626                 while (size >= 1) {
1627                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1628                         offset += 1;
1629                         size -= 1;
1630                 }
1631                 return;
1632         }       
1633
1634         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1635                 if (offset % 8) {
1636                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1637                         offset += 4;
1638                         size -= 4;
1639                 }
1640                 while (size >= 8) {
1641                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1642                         offset += 8;
1643                         size -= 8;
1644                 }
1645         }       
1646
1647         while (size >= 4) {
1648                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1649                 offset += 4;
1650                 size -= 4;
1651         }
1652         while (size >= 2) {
1653                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1654                 offset += 2;
1655                 size -= 2;
1656         }
1657         while (size >= 1) {
1658                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1659                 offset += 1;
1660                 size -= 1;
1661         }
1662 }
1663
1664 void 
1665 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1666 {
1667         int cur_reg;
1668
1669         if (align == 0)
1670                 align = 4;
1671
1672         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1673         g_assert (size < 10000);
1674
1675         if (align < 4) {
1676                 /* This could be optimized further if neccesary */
1677                 while (size >= 1) {
1678                         cur_reg = alloc_preg (cfg);
1679                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1680                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1681                         doffset += 1;
1682                         soffset += 1;
1683                         size -= 1;
1684                 }
1685         }
1686
1687         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1688                 while (size >= 8) {
1689                         cur_reg = alloc_preg (cfg);
1690                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1691                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1692                         doffset += 8;
1693                         soffset += 8;
1694                         size -= 8;
1695                 }
1696         }       
1697
1698         while (size >= 4) {
1699                 cur_reg = alloc_preg (cfg);
1700                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1701                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1702                 doffset += 4;
1703                 soffset += 4;
1704                 size -= 4;
1705         }
1706         while (size >= 2) {
1707                 cur_reg = alloc_preg (cfg);
1708                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1709                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1710                 doffset += 2;
1711                 soffset += 2;
1712                 size -= 2;
1713         }
1714         while (size >= 1) {
1715                 cur_reg = alloc_preg (cfg);
1716                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1717                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1718                 doffset += 1;
1719                 soffset += 1;
1720                 size -= 1;
1721         }
1722 }
1723
1724 static MonoInst*
1725 mono_create_fast_tls_getter (MonoCompile *cfg, MonoTlsKey key)
1726 {
1727         int tls_offset = mono_tls_get_tls_offset (key);
1728
1729         if (cfg->compile_aot)
1730                 return NULL;
1731
1732         if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
1733                 MonoInst *ins;
1734                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
1735                 ins->dreg = mono_alloc_preg (cfg);
1736                 ins->inst_offset = tls_offset;
1737                 return ins;
1738         }
1739         return NULL;
1740 }
1741
1742 static MonoInst*
1743 mono_create_fast_tls_setter (MonoCompile *cfg, MonoInst* value, MonoTlsKey key)
1744 {
1745         int tls_offset = mono_tls_get_tls_offset (key);
1746
1747         if (cfg->compile_aot)
1748                 return NULL;
1749
1750         if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
1751                 MonoInst *ins;
1752                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1753                 ins->sreg1 = value->dreg;
1754                 ins->inst_offset = tls_offset;
1755                 return ins;
1756         }
1757         return NULL;
1758 }
1759
1760
1761 MonoInst*
1762 mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key)
1763 {
1764         MonoInst *fast_tls = NULL;
1765
1766         if (!mini_get_debug_options ()->use_fallback_tls)
1767                 fast_tls = mono_create_fast_tls_getter (cfg, key);
1768
1769         if (fast_tls) {
1770                 MONO_ADD_INS (cfg->cbb, fast_tls);
1771                 return fast_tls;
1772         }
1773
1774         if (cfg->compile_aot) {
1775                 MonoInst *addr;
1776                 /*
1777                  * tls getters are critical pieces of code and we don't want to resolve them
1778                  * through the standard plt/tramp mechanism since we might expose ourselves
1779                  * to crashes and infinite recursions.
1780                  */
1781                 EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GET_TLS_TRAMP, (void*)key);
1782                 return mono_emit_calli (cfg, helper_sig_get_tls_tramp, NULL, addr, NULL, NULL);
1783         } else {
1784                 gpointer getter = mono_tls_get_tls_getter (key, FALSE);
1785                 return mono_emit_jit_icall (cfg, getter, NULL);
1786         }
1787 }
1788
1789 static MonoInst*
1790 mono_create_tls_set (MonoCompile *cfg, MonoInst *value, MonoTlsKey key)
1791 {
1792         MonoInst *fast_tls = NULL;
1793
1794         if (!mini_get_debug_options ()->use_fallback_tls)
1795                 fast_tls = mono_create_fast_tls_setter (cfg, value, key);
1796
1797         if (fast_tls) {
1798                 MONO_ADD_INS (cfg->cbb, fast_tls);
1799                 return fast_tls;
1800         }
1801
1802         if (cfg->compile_aot) {
1803                 MonoInst *addr;
1804                 EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_SET_TLS_TRAMP, (void*)key);
1805                 return mono_emit_calli (cfg, helper_sig_set_tls_tramp, &value, addr, NULL, NULL);
1806         } else {
1807                 gpointer setter = mono_tls_get_tls_setter (key, FALSE);
1808                 return mono_emit_jit_icall (cfg, setter, &value);
1809         }
1810 }
1811
1812 /*
1813  * emit_push_lmf:
1814  *
1815  *   Emit IR to push the current LMF onto the LMF stack.
1816  */
1817 static void
1818 emit_push_lmf (MonoCompile *cfg)
1819 {
1820         /*
1821          * Emit IR to push the LMF:
1822          * lmf_addr = <lmf_addr from tls>
1823          * lmf->lmf_addr = lmf_addr
1824          * lmf->prev_lmf = *lmf_addr
1825          * *lmf_addr = lmf
1826          */
1827         MonoInst *ins, *lmf_ins;
1828
1829         if (!cfg->lmf_ir)
1830                 return;
1831
1832         if (cfg->lmf_ir_mono_lmf) {
1833                 MonoInst *lmf_vara_ins, *lmf_ins;
1834                 /* Load current lmf */
1835                 lmf_ins = mono_create_tls_get (cfg, TLS_KEY_LMF);
1836                 g_assert (lmf_ins);
1837                 EMIT_NEW_VARLOADA (cfg, lmf_vara_ins, cfg->lmf_var, NULL);
1838                 /* Save previous_lmf */
1839                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_vara_ins->dreg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1840                 /* Set new LMF */
1841                 mono_create_tls_set (cfg, lmf_vara_ins, TLS_KEY_LMF);
1842         } else {
1843                 int lmf_reg, prev_lmf_reg;
1844                 /*
1845                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1846                  */
1847                 if (!cfg->lmf_addr_var)
1848                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1849
1850 #ifdef HOST_WIN32
1851                 ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
1852                 g_assert (ins);
1853                 int jit_tls_dreg = ins->dreg;
1854
1855                 lmf_reg = alloc_preg (cfg);
1856                 EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
1857 #else
1858                 lmf_ins = mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR);
1859                 g_assert (lmf_ins);
1860 #endif
1861                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
1862
1863                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1864                 lmf_reg = ins->dreg;
1865
1866                 prev_lmf_reg = alloc_preg (cfg);
1867                 /* Save previous_lmf */
1868                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
1869                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
1870                 /* Set new lmf */
1871                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
1872         }
1873 }
1874
1875 /*
1876  * emit_pop_lmf:
1877  *
1878  *   Emit IR to pop the current LMF from the LMF stack.
1879  */
1880 static void
1881 emit_pop_lmf (MonoCompile *cfg)
1882 {
1883         int lmf_reg, lmf_addr_reg;
1884         MonoInst *ins;
1885
1886         if (!cfg->lmf_ir)
1887                 return;
1888
1889         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1890         lmf_reg = ins->dreg;
1891
1892         if (cfg->lmf_ir_mono_lmf) {
1893                 /* Load previous_lmf */
1894                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, alloc_preg (cfg), lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1895                 /* Set new LMF */
1896                 mono_create_tls_set (cfg, ins, TLS_KEY_LMF);
1897         } else {
1898                 int prev_lmf_reg;
1899                 /*
1900                  * Emit IR to pop the LMF:
1901                  * *(lmf->lmf_addr) = lmf->prev_lmf
1902                  */
1903                 /* This could be called before emit_push_lmf () */
1904                 if (!cfg->lmf_addr_var)
1905                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1906                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
1907
1908                 prev_lmf_reg = alloc_preg (cfg);
1909                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1910                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
1911         }
1912 }
1913
1914 static void
1915 emit_instrumentation_call (MonoCompile *cfg, void *func)
1916 {
1917         MonoInst *iargs [1];
1918
1919         /*
1920          * Avoid instrumenting inlined methods since it can
1921          * distort profiling results.
1922          */
1923         if (cfg->method != cfg->current_method)
1924                 return;
1925
1926         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
1927                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
1928                 mono_emit_jit_icall (cfg, func, iargs);
1929         }
1930 }
1931
1932 static int
1933 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
1934 {
1935 handle_enum:
1936         type = mini_get_underlying_type (type);
1937         switch (type->type) {
1938         case MONO_TYPE_VOID:
1939                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
1940         case MONO_TYPE_I1:
1941         case MONO_TYPE_U1:
1942         case MONO_TYPE_I2:
1943         case MONO_TYPE_U2:
1944         case MONO_TYPE_I4:
1945         case MONO_TYPE_U4:
1946                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1947         case MONO_TYPE_I:
1948         case MONO_TYPE_U:
1949         case MONO_TYPE_PTR:
1950         case MONO_TYPE_FNPTR:
1951                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1952         case MONO_TYPE_CLASS:
1953         case MONO_TYPE_STRING:
1954         case MONO_TYPE_OBJECT:
1955         case MONO_TYPE_SZARRAY:
1956         case MONO_TYPE_ARRAY:    
1957                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1958         case MONO_TYPE_I8:
1959         case MONO_TYPE_U8:
1960                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
1961         case MONO_TYPE_R4:
1962                 if (cfg->r4fp)
1963                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
1964                 else
1965                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1966         case MONO_TYPE_R8:
1967                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1968         case MONO_TYPE_VALUETYPE:
1969                 if (type->data.klass->enumtype) {
1970                         type = mono_class_enum_basetype (type->data.klass);
1971                         goto handle_enum;
1972                 } else
1973                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1974         case MONO_TYPE_TYPEDBYREF:
1975                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1976         case MONO_TYPE_GENERICINST:
1977                 type = &type->data.generic_class->container_class->byval_arg;
1978                 goto handle_enum;
1979         case MONO_TYPE_VAR:
1980         case MONO_TYPE_MVAR:
1981                 /* gsharedvt */
1982                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1983         default:
1984                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1985         }
1986         return -1;
1987 }
1988
1989 //XXX this ignores if t is byref
1990 #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)))))
1991
1992 /*
1993  * target_type_is_incompatible:
1994  * @cfg: MonoCompile context
1995  *
1996  * Check that the item @arg on the evaluation stack can be stored
1997  * in the target type (can be a local, or field, etc).
1998  * The cfg arg can be used to check if we need verification or just
1999  * validity checks.
2000  *
2001  * Returns: non-0 value if arg can't be stored on a target.
2002  */
2003 static int
2004 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2005 {
2006         MonoType *simple_type;
2007         MonoClass *klass;
2008
2009         if (target->byref) {
2010                 /* FIXME: check that the pointed to types match */
2011                 if (arg->type == STACK_MP) {
2012                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
2013                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
2014                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
2015
2016                         /* if the target is native int& or same type */
2017                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
2018                                 return 0;
2019
2020                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
2021                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
2022                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
2023                                 return 0;
2024                         return 1;
2025                 }
2026                 if (arg->type == STACK_PTR)
2027                         return 0;
2028                 return 1;
2029         }
2030
2031         simple_type = mini_get_underlying_type (target);
2032         switch (simple_type->type) {
2033         case MONO_TYPE_VOID:
2034                 return 1;
2035         case MONO_TYPE_I1:
2036         case MONO_TYPE_U1:
2037         case MONO_TYPE_I2:
2038         case MONO_TYPE_U2:
2039         case MONO_TYPE_I4:
2040         case MONO_TYPE_U4:
2041                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2042                         return 1;
2043                 return 0;
2044         case MONO_TYPE_PTR:
2045                 /* STACK_MP is needed when setting pinned locals */
2046                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2047                         return 1;
2048                 return 0;
2049         case MONO_TYPE_I:
2050         case MONO_TYPE_U:
2051         case MONO_TYPE_FNPTR:
2052                 /* 
2053                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2054                  * in native int. (#688008).
2055                  */
2056                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2057                         return 1;
2058                 return 0;
2059         case MONO_TYPE_CLASS:
2060         case MONO_TYPE_STRING:
2061         case MONO_TYPE_OBJECT:
2062         case MONO_TYPE_SZARRAY:
2063         case MONO_TYPE_ARRAY:    
2064                 if (arg->type != STACK_OBJ)
2065                         return 1;
2066                 /* FIXME: check type compatibility */
2067                 return 0;
2068         case MONO_TYPE_I8:
2069         case MONO_TYPE_U8:
2070                 if (arg->type != STACK_I8)
2071                         return 1;
2072                 return 0;
2073         case MONO_TYPE_R4:
2074                 if (arg->type != cfg->r4_stack_type)
2075                         return 1;
2076                 return 0;
2077         case MONO_TYPE_R8:
2078                 if (arg->type != STACK_R8)
2079                         return 1;
2080                 return 0;
2081         case MONO_TYPE_VALUETYPE:
2082                 if (arg->type != STACK_VTYPE)
2083                         return 1;
2084                 klass = mono_class_from_mono_type (simple_type);
2085                 if (klass != arg->klass)
2086                         return 1;
2087                 return 0;
2088         case MONO_TYPE_TYPEDBYREF:
2089                 if (arg->type != STACK_VTYPE)
2090                         return 1;
2091                 klass = mono_class_from_mono_type (simple_type);
2092                 if (klass != arg->klass)
2093                         return 1;
2094                 return 0;
2095         case MONO_TYPE_GENERICINST:
2096                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2097                         MonoClass *target_class;
2098                         if (arg->type != STACK_VTYPE)
2099                                 return 1;
2100                         klass = mono_class_from_mono_type (simple_type);
2101                         target_class = mono_class_from_mono_type (target);
2102                         /* The second cases is needed when doing partial sharing */
2103                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2104                                 return 1;
2105                         return 0;
2106                 } else {
2107                         if (arg->type != STACK_OBJ)
2108                                 return 1;
2109                         /* FIXME: check type compatibility */
2110                         return 0;
2111                 }
2112         case MONO_TYPE_VAR:
2113         case MONO_TYPE_MVAR:
2114                 g_assert (cfg->gshared);
2115                 if (mini_type_var_is_vt (simple_type)) {
2116                         if (arg->type != STACK_VTYPE)
2117                                 return 1;
2118                 } else {
2119                         if (arg->type != STACK_OBJ)
2120                                 return 1;
2121                 }
2122                 return 0;
2123         default:
2124                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2125         }
2126         return 1;
2127 }
2128
2129 /*
2130  * Prepare arguments for passing to a function call.
2131  * Return a non-zero value if the arguments can't be passed to the given
2132  * signature.
2133  * The type checks are not yet complete and some conversions may need
2134  * casts on 32 or 64 bit architectures.
2135  *
2136  * FIXME: implement this using target_type_is_incompatible ()
2137  */
2138 static int
2139 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2140 {
2141         MonoType *simple_type;
2142         int i;
2143
2144         if (sig->hasthis) {
2145                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2146                         return 1;
2147                 args++;
2148         }
2149         for (i = 0; i < sig->param_count; ++i) {
2150                 if (sig->params [i]->byref) {
2151                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2152                                 return 1;
2153                         continue;
2154                 }
2155                 simple_type = mini_get_underlying_type (sig->params [i]);
2156 handle_enum:
2157                 switch (simple_type->type) {
2158                 case MONO_TYPE_VOID:
2159                         return 1;
2160                         continue;
2161                 case MONO_TYPE_I1:
2162                 case MONO_TYPE_U1:
2163                 case MONO_TYPE_I2:
2164                 case MONO_TYPE_U2:
2165                 case MONO_TYPE_I4:
2166                 case MONO_TYPE_U4:
2167                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2168                                 return 1;
2169                         continue;
2170                 case MONO_TYPE_I:
2171                 case MONO_TYPE_U:
2172                 case MONO_TYPE_PTR:
2173                 case MONO_TYPE_FNPTR:
2174                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2175                                 return 1;
2176                         continue;
2177                 case MONO_TYPE_CLASS:
2178                 case MONO_TYPE_STRING:
2179                 case MONO_TYPE_OBJECT:
2180                 case MONO_TYPE_SZARRAY:
2181                 case MONO_TYPE_ARRAY:    
2182                         if (args [i]->type != STACK_OBJ)
2183                                 return 1;
2184                         continue;
2185                 case MONO_TYPE_I8:
2186                 case MONO_TYPE_U8:
2187                         if (args [i]->type != STACK_I8)
2188                                 return 1;
2189                         continue;
2190                 case MONO_TYPE_R4:
2191                         if (args [i]->type != cfg->r4_stack_type)
2192                                 return 1;
2193                         continue;
2194                 case MONO_TYPE_R8:
2195                         if (args [i]->type != STACK_R8)
2196                                 return 1;
2197                         continue;
2198                 case MONO_TYPE_VALUETYPE:
2199                         if (simple_type->data.klass->enumtype) {
2200                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2201                                 goto handle_enum;
2202                         }
2203                         if (args [i]->type != STACK_VTYPE)
2204                                 return 1;
2205                         continue;
2206                 case MONO_TYPE_TYPEDBYREF:
2207                         if (args [i]->type != STACK_VTYPE)
2208                                 return 1;
2209                         continue;
2210                 case MONO_TYPE_GENERICINST:
2211                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2212                         goto handle_enum;
2213                 case MONO_TYPE_VAR:
2214                 case MONO_TYPE_MVAR:
2215                         /* gsharedvt */
2216                         if (args [i]->type != STACK_VTYPE)
2217                                 return 1;
2218                         continue;
2219                 default:
2220                         g_error ("unknown type 0x%02x in check_call_signature",
2221                                  simple_type->type);
2222                 }
2223         }
2224         return 0;
2225 }
2226
2227 static int
2228 callvirt_to_call (int opcode)
2229 {
2230         switch (opcode) {
2231         case OP_CALL_MEMBASE:
2232                 return OP_CALL;
2233         case OP_VOIDCALL_MEMBASE:
2234                 return OP_VOIDCALL;
2235         case OP_FCALL_MEMBASE:
2236                 return OP_FCALL;
2237         case OP_RCALL_MEMBASE:
2238                 return OP_RCALL;
2239         case OP_VCALL_MEMBASE:
2240                 return OP_VCALL;
2241         case OP_LCALL_MEMBASE:
2242                 return OP_LCALL;
2243         default:
2244                 g_assert_not_reached ();
2245         }
2246
2247         return -1;
2248 }
2249
2250 static int
2251 callvirt_to_call_reg (int opcode)
2252 {
2253         switch (opcode) {
2254         case OP_CALL_MEMBASE:
2255                 return OP_CALL_REG;
2256         case OP_VOIDCALL_MEMBASE:
2257                 return OP_VOIDCALL_REG;
2258         case OP_FCALL_MEMBASE:
2259                 return OP_FCALL_REG;
2260         case OP_RCALL_MEMBASE:
2261                 return OP_RCALL_REG;
2262         case OP_VCALL_MEMBASE:
2263                 return OP_VCALL_REG;
2264         case OP_LCALL_MEMBASE:
2265                 return OP_LCALL_REG;
2266         default:
2267                 g_assert_not_reached ();
2268         }
2269
2270         return -1;
2271 }
2272
2273 /* Either METHOD or IMT_ARG needs to be set */
2274 static void
2275 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2276 {
2277         int method_reg;
2278
2279         if (COMPILE_LLVM (cfg)) {
2280                 if (imt_arg) {
2281                         method_reg = alloc_preg (cfg);
2282                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2283                 } else {
2284                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2285                         method_reg = ins->dreg;
2286                 }
2287
2288 #ifdef ENABLE_LLVM
2289                 call->imt_arg_reg = method_reg;
2290 #endif
2291                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2292                 return;
2293         }
2294
2295         if (imt_arg) {
2296                 method_reg = alloc_preg (cfg);
2297                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2298         } else {
2299                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2300                 method_reg = ins->dreg;
2301         }
2302
2303         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2304 }
2305
2306 static MonoJumpInfo *
2307 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2308 {
2309         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2310
2311         ji->ip.i = ip;
2312         ji->type = type;
2313         ji->data.target = target;
2314
2315         return ji;
2316 }
2317
2318 static int
2319 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2320 {
2321         if (cfg->gshared)
2322                 return mono_class_check_context_used (klass);
2323         else
2324                 return 0;
2325 }
2326
2327 static int
2328 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2329 {
2330         if (cfg->gshared)
2331                 return mono_method_check_context_used (method);
2332         else
2333                 return 0;
2334 }
2335
2336 /*
2337  * check_method_sharing:
2338  *
2339  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2340  */
2341 static void
2342 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2343 {
2344         gboolean pass_vtable = FALSE;
2345         gboolean pass_mrgctx = FALSE;
2346
2347         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2348                 (mono_class_is_ginst (cmethod->klass) || mono_class_is_gtd (cmethod->klass))) {
2349                 gboolean sharable = FALSE;
2350
2351                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2352                         sharable = TRUE;
2353
2354                 /*
2355                  * Pass vtable iff target method might
2356                  * be shared, which means that sharing
2357                  * is enabled for its class and its
2358                  * context is sharable (and it's not a
2359                  * generic method).
2360                  */
2361                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2362                         pass_vtable = TRUE;
2363         }
2364
2365         if (mini_method_get_context (cmethod) &&
2366                 mini_method_get_context (cmethod)->method_inst) {
2367                 g_assert (!pass_vtable);
2368
2369                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2370                         pass_mrgctx = TRUE;
2371                 } else {
2372                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2373                                 pass_mrgctx = TRUE;
2374                 }
2375         }
2376
2377         if (out_pass_vtable)
2378                 *out_pass_vtable = pass_vtable;
2379         if (out_pass_mrgctx)
2380                 *out_pass_mrgctx = pass_mrgctx;
2381 }
2382
2383 inline static MonoCallInst *
2384 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2385                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2386 {
2387         MonoType *sig_ret;
2388         MonoCallInst *call;
2389 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2390         int i;
2391 #endif
2392
2393         if (cfg->llvm_only)
2394                 tail = FALSE;
2395
2396         if (tail) {
2397                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2398
2399                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2400         } else
2401                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2402
2403         call->args = args;
2404         call->signature = sig;
2405         call->rgctx_reg = rgctx;
2406         sig_ret = mini_get_underlying_type (sig->ret);
2407
2408         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2409
2410         if (tail) {
2411                 if (mini_type_is_vtype (sig_ret)) {
2412                         call->vret_var = cfg->vret_addr;
2413                         //g_assert_not_reached ();
2414                 }
2415         } else if (mini_type_is_vtype (sig_ret)) {
2416                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2417                 MonoInst *loada;
2418
2419                 temp->backend.is_pinvoke = sig->pinvoke;
2420
2421                 /*
2422                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2423                  * address of return value to increase optimization opportunities.
2424                  * Before vtype decomposition, the dreg of the call ins itself represents the
2425                  * fact the call modifies the return value. After decomposition, the call will
2426                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2427                  * will be transformed into an LDADDR.
2428                  */
2429                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2430                 loada->dreg = alloc_preg (cfg);
2431                 loada->inst_p0 = temp;
2432                 /* We reference the call too since call->dreg could change during optimization */
2433                 loada->inst_p1 = call;
2434                 MONO_ADD_INS (cfg->cbb, loada);
2435
2436                 call->inst.dreg = temp->dreg;
2437
2438                 call->vret_var = loada;
2439         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2440                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2441
2442 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2443         if (COMPILE_SOFT_FLOAT (cfg)) {
2444                 /* 
2445                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2446                  * an icall, but that cannot be done during the call sequence since it would clobber
2447                  * the call registers + the stack. So we do it before emitting the call.
2448                  */
2449                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2450                         MonoType *t;
2451                         MonoInst *in = call->args [i];
2452
2453                         if (i >= sig->hasthis)
2454                                 t = sig->params [i - sig->hasthis];
2455                         else
2456                                 t = &mono_defaults.int_class->byval_arg;
2457                         t = mono_type_get_underlying_type (t);
2458
2459                         if (!t->byref && t->type == MONO_TYPE_R4) {
2460                                 MonoInst *iargs [1];
2461                                 MonoInst *conv;
2462
2463                                 iargs [0] = in;
2464                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2465
2466                                 /* The result will be in an int vreg */
2467                                 call->args [i] = conv;
2468                         }
2469                 }
2470         }
2471 #endif
2472
2473         call->need_unbox_trampoline = unbox_trampoline;
2474
2475 #ifdef ENABLE_LLVM
2476         if (COMPILE_LLVM (cfg))
2477                 mono_llvm_emit_call (cfg, call);
2478         else
2479                 mono_arch_emit_call (cfg, call);
2480 #else
2481         mono_arch_emit_call (cfg, call);
2482 #endif
2483
2484         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2485         cfg->flags |= MONO_CFG_HAS_CALLS;
2486         
2487         return call;
2488 }
2489
2490 static void
2491 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2492 {
2493         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2494         cfg->uses_rgctx_reg = TRUE;
2495         call->rgctx_reg = TRUE;
2496 #ifdef ENABLE_LLVM
2497         call->rgctx_arg_reg = rgctx_reg;
2498 #endif
2499 }       
2500
2501 inline static MonoInst*
2502 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2503 {
2504         MonoCallInst *call;
2505         MonoInst *ins;
2506         int rgctx_reg = -1;
2507         gboolean check_sp = FALSE;
2508
2509         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2510                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2511
2512                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2513                         check_sp = TRUE;
2514         }
2515
2516         if (rgctx_arg) {
2517                 rgctx_reg = mono_alloc_preg (cfg);
2518                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2519         }
2520
2521         if (check_sp) {
2522                 if (!cfg->stack_inbalance_var)
2523                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2524
2525                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2526                 ins->dreg = cfg->stack_inbalance_var->dreg;
2527                 MONO_ADD_INS (cfg->cbb, ins);
2528         }
2529
2530         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2531
2532         call->inst.sreg1 = addr->dreg;
2533
2534         if (imt_arg)
2535                 emit_imt_argument (cfg, call, NULL, imt_arg);
2536
2537         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2538
2539         if (check_sp) {
2540                 int sp_reg;
2541
2542                 sp_reg = mono_alloc_preg (cfg);
2543
2544                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2545                 ins->dreg = sp_reg;
2546                 MONO_ADD_INS (cfg->cbb, ins);
2547
2548                 /* Restore the stack so we don't crash when throwing the exception */
2549                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2550                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2551                 MONO_ADD_INS (cfg->cbb, ins);
2552
2553                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2554                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2555         }
2556
2557         if (rgctx_arg)
2558                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2559
2560         return (MonoInst*)call;
2561 }
2562
2563 static MonoInst*
2564 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2565
2566 static MonoInst*
2567 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2568
2569 static MonoInst*
2570 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2571                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2572 {
2573 #ifndef DISABLE_REMOTING
2574         gboolean might_be_remote = FALSE;
2575 #endif
2576         gboolean virtual_ = this_ins != NULL;
2577         gboolean enable_for_aot = TRUE;
2578         int context_used;
2579         MonoCallInst *call;
2580         MonoInst *call_target = NULL;
2581         int rgctx_reg = 0;
2582         gboolean need_unbox_trampoline;
2583
2584         if (!sig)
2585                 sig = mono_method_signature (method);
2586
2587         if (cfg->llvm_only && (mono_class_is_interface (method->klass)))
2588                 g_assert_not_reached ();
2589
2590         if (rgctx_arg) {
2591                 rgctx_reg = mono_alloc_preg (cfg);
2592                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2593         }
2594
2595         if (method->string_ctor) {
2596                 /* Create the real signature */
2597                 /* FIXME: Cache these */
2598                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2599                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2600
2601                 sig = ctor_sig;
2602         }
2603
2604         context_used = mini_method_check_context_used (cfg, method);
2605
2606 #ifndef DISABLE_REMOTING
2607         might_be_remote = this_ins && sig->hasthis &&
2608                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2609                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2610
2611         if (might_be_remote && context_used) {
2612                 MonoInst *addr;
2613
2614                 g_assert (cfg->gshared);
2615
2616                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2617
2618                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2619         }
2620 #endif
2621
2622         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2623                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2624
2625         need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass);
2626
2627         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2628
2629 #ifndef DISABLE_REMOTING
2630         if (might_be_remote)
2631                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2632         else
2633 #endif
2634                 call->method = method;
2635         call->inst.flags |= MONO_INST_HAS_METHOD;
2636         call->inst.inst_left = this_ins;
2637         call->tail_call = tail;
2638
2639         if (virtual_) {
2640                 int vtable_reg, slot_reg, this_reg;
2641                 int offset;
2642
2643                 this_reg = this_ins->dreg;
2644
2645                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2646                         MonoInst *dummy_use;
2647
2648                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2649
2650                         /* Make a call to delegate->invoke_impl */
2651                         call->inst.inst_basereg = this_reg;
2652                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2653                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2654
2655                         /* We must emit a dummy use here because the delegate trampoline will
2656                         replace the 'this' argument with the delegate target making this activation
2657                         no longer a root for the delegate.
2658                         This is an issue for delegates that target collectible code such as dynamic
2659                         methods of GC'able assemblies.
2660
2661                         For a test case look into #667921.
2662
2663                         FIXME: a dummy use is not the best way to do it as the local register allocator
2664                         will put it on a caller save register and spil it around the call. 
2665                         Ideally, we would either put it on a callee save register or only do the store part.  
2666                          */
2667                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2668
2669                         return (MonoInst*)call;
2670                 }
2671
2672                 if ((!cfg->compile_aot || enable_for_aot) && 
2673                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2674                          (MONO_METHOD_IS_FINAL (method) &&
2675                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2676                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2677                         /* 
2678                          * the method is not virtual, we just need to ensure this is not null
2679                          * and then we can call the method directly.
2680                          */
2681 #ifndef DISABLE_REMOTING
2682                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2683                                 /* 
2684                                  * The check above ensures method is not gshared, this is needed since
2685                                  * gshared methods can't have wrappers.
2686                                  */
2687                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2688                         }
2689 #endif
2690
2691                         if (!method->string_ctor)
2692                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2693
2694                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2695                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2696                         /*
2697                          * the method is virtual, but we can statically dispatch since either
2698                          * it's class or the method itself are sealed.
2699                          * But first we need to ensure it's not a null reference.
2700                          */
2701                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2702
2703                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2704                 } else if (call_target) {
2705                         vtable_reg = alloc_preg (cfg);
2706                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2707
2708                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2709                         call->inst.sreg1 = call_target->dreg;
2710                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2711                 } else {
2712                         vtable_reg = alloc_preg (cfg);
2713                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2714                         if (mono_class_is_interface (method->klass)) {
2715                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2716                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2717                                 slot_reg = vtable_reg;
2718                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2719                         } else {
2720                                 slot_reg = vtable_reg;
2721                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2722                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2723                                 if (imt_arg) {
2724                                         g_assert (mono_method_signature (method)->generic_param_count);
2725                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2726                                 }
2727                         }
2728
2729                         call->inst.sreg1 = slot_reg;
2730                         call->inst.inst_offset = offset;
2731                         call->is_virtual = TRUE;
2732                 }
2733         }
2734
2735         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2736
2737         if (rgctx_arg)
2738                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2739
2740         return (MonoInst*)call;
2741 }
2742
2743 MonoInst*
2744 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2745 {
2746         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2747 }
2748
2749 MonoInst*
2750 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2751                                            MonoInst **args)
2752 {
2753         MonoCallInst *call;
2754
2755         g_assert (sig);
2756
2757         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2758         call->fptr = func;
2759
2760         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2761
2762         return (MonoInst*)call;
2763 }
2764
2765 MonoInst*
2766 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2767 {
2768         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2769
2770         g_assert (info);
2771
2772         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2773 }
2774
2775 /*
2776  * mono_emit_abs_call:
2777  *
2778  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2779  */
2780 inline static MonoInst*
2781 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2782                                         MonoMethodSignature *sig, MonoInst **args)
2783 {
2784         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2785         MonoInst *ins;
2786
2787         /* 
2788          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2789          * handle it.
2790          */
2791         if (cfg->abs_patches == NULL)
2792                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2793         g_hash_table_insert (cfg->abs_patches, ji, ji);
2794         ins = mono_emit_native_call (cfg, ji, sig, args);
2795         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2796         return ins;
2797 }
2798
2799 static MonoMethodSignature*
2800 sig_to_rgctx_sig (MonoMethodSignature *sig)
2801 {
2802         // FIXME: memory allocation
2803         MonoMethodSignature *res;
2804         int i;
2805
2806         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2807         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2808         res->param_count = sig->param_count + 1;
2809         for (i = 0; i < sig->param_count; ++i)
2810                 res->params [i] = sig->params [i];
2811         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
2812         return res;
2813 }
2814
2815 /* Make an indirect call to FSIG passing an additional argument */
2816 static MonoInst*
2817 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
2818 {
2819         MonoMethodSignature *csig;
2820         MonoInst *args_buf [16];
2821         MonoInst **args;
2822         int i, pindex, tmp_reg;
2823
2824         /* Make a call with an rgctx/extra arg */
2825         if (fsig->param_count + 2 < 16)
2826                 args = args_buf;
2827         else
2828                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
2829         pindex = 0;
2830         if (fsig->hasthis)
2831                 args [pindex ++] = orig_args [0];
2832         for (i = 0; i < fsig->param_count; ++i)
2833                 args [pindex ++] = orig_args [fsig->hasthis + i];
2834         tmp_reg = alloc_preg (cfg);
2835         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
2836         csig = sig_to_rgctx_sig (fsig);
2837         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
2838 }
2839
2840 /* Emit an indirect call to the function descriptor ADDR */
2841 static MonoInst*
2842 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
2843 {
2844         int addr_reg, arg_reg;
2845         MonoInst *call_target;
2846
2847         g_assert (cfg->llvm_only);
2848
2849         /*
2850          * addr points to a <addr, arg> pair, load both of them, and
2851          * make a call to addr, passing arg as an extra arg.
2852          */
2853         addr_reg = alloc_preg (cfg);
2854         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
2855         arg_reg = alloc_preg (cfg);
2856         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
2857
2858         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
2859 }
2860
2861 static gboolean
2862 direct_icalls_enabled (MonoCompile *cfg)
2863 {
2864         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
2865 #ifdef TARGET_AMD64
2866         if (cfg->compile_llvm && !cfg->llvm_only)
2867                 return FALSE;
2868 #endif
2869         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
2870                 return FALSE;
2871         return TRUE;
2872 }
2873
2874 MonoInst*
2875 mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
2876 {
2877         /*
2878          * Call the jit icall without a wrapper if possible.
2879          * The wrapper is needed for the following reasons:
2880          * - to handle exceptions thrown using mono_raise_exceptions () from the
2881          *   icall function. The EH code needs the lmf frame pushed by the
2882          *   wrapper to be able to unwind back to managed code.
2883          * - to be able to do stack walks for asynchronously suspended
2884          *   threads when debugging.
2885          */
2886         if (info->no_raise && direct_icalls_enabled (cfg)) {
2887                 char *name;
2888                 int costs;
2889
2890                 if (!info->wrapper_method) {
2891                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
2892                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
2893                         g_free (name);
2894                         mono_memory_barrier ();
2895                 }
2896
2897                 /*
2898                  * Inline the wrapper method, which is basically a call to the C icall, and
2899                  * an exception check.
2900                  */
2901                 costs = inline_method (cfg, info->wrapper_method, NULL,
2902                                                            args, NULL, il_offset, TRUE);
2903                 g_assert (costs > 0);
2904                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
2905
2906                 return args [0];
2907         } else {
2908                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2909         }
2910 }
2911  
2912 static MonoInst*
2913 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2914 {
2915         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2916                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2917                         int widen_op = -1;
2918
2919                         /* 
2920                          * Native code might return non register sized integers 
2921                          * without initializing the upper bits.
2922                          */
2923                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2924                         case OP_LOADI1_MEMBASE:
2925                                 widen_op = OP_ICONV_TO_I1;
2926                                 break;
2927                         case OP_LOADU1_MEMBASE:
2928                                 widen_op = OP_ICONV_TO_U1;
2929                                 break;
2930                         case OP_LOADI2_MEMBASE:
2931                                 widen_op = OP_ICONV_TO_I2;
2932                                 break;
2933                         case OP_LOADU2_MEMBASE:
2934                                 widen_op = OP_ICONV_TO_U2;
2935                                 break;
2936                         default:
2937                                 break;
2938                         }
2939
2940                         if (widen_op != -1) {
2941                                 int dreg = alloc_preg (cfg);
2942                                 MonoInst *widen;
2943
2944                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2945                                 widen->type = ins->type;
2946                                 ins = widen;
2947                         }
2948                 }
2949         }
2950
2951         return ins;
2952 }
2953
2954
2955 static void
2956 emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
2957 {
2958         MonoInst *args [16];
2959
2960         args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
2961         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
2962
2963         mono_emit_jit_icall (cfg, mono_throw_method_access, args);
2964 }
2965
2966 static MonoMethod*
2967 get_memcpy_method (void)
2968 {
2969         static MonoMethod *memcpy_method = NULL;
2970         if (!memcpy_method) {
2971                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2972                 if (!memcpy_method)
2973                         g_error ("Old corlib found. Install a new one");
2974         }
2975         return memcpy_method;
2976 }
2977
2978 static void
2979 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
2980 {
2981         MonoClassField *field;
2982         gpointer iter = NULL;
2983
2984         while ((field = mono_class_get_fields (klass, &iter))) {
2985                 int foffset;
2986
2987                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2988                         continue;
2989                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2990                 if (mini_type_is_reference (mono_field_get_type (field))) {
2991                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2992                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2993                 } else {
2994                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2995                         if (field_class->has_references)
2996                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
2997                 }
2998         }
2999 }
3000
3001 static void
3002 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3003 {
3004         int card_table_shift_bits;
3005         gpointer card_table_mask;
3006         guint8 *card_table;
3007         MonoInst *dummy_use;
3008         int nursery_shift_bits;
3009         size_t nursery_size;
3010
3011         if (!cfg->gen_write_barriers)
3012                 return;
3013
3014         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3015
3016         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3017
3018         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3019                 MonoInst *wbarrier;
3020
3021                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3022                 wbarrier->sreg1 = ptr->dreg;
3023                 wbarrier->sreg2 = value->dreg;
3024                 MONO_ADD_INS (cfg->cbb, wbarrier);
3025         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3026                 int offset_reg = alloc_preg (cfg);
3027                 int card_reg;
3028                 MonoInst *ins;
3029
3030                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3031                 if (card_table_mask)
3032                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3033
3034                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3035                  * IMM's larger than 32bits.
3036                  */
3037                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3038                 card_reg = ins->dreg;
3039
3040                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3041                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3042         } else {
3043                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3044                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3045         }
3046
3047         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3048 }
3049
3050 static gboolean
3051 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3052 {
3053         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3054         unsigned need_wb = 0;
3055
3056         if (align == 0)
3057                 align = 4;
3058
3059         /*types with references can't have alignment smaller than sizeof(void*) */
3060         if (align < SIZEOF_VOID_P)
3061                 return FALSE;
3062
3063         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3064         if (size > 32 * SIZEOF_VOID_P)
3065                 return FALSE;
3066
3067         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3068
3069         /* We don't unroll more than 5 stores to avoid code bloat. */
3070         if (size > 5 * SIZEOF_VOID_P) {
3071                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3072                 size += (SIZEOF_VOID_P - 1);
3073                 size &= ~(SIZEOF_VOID_P - 1);
3074
3075                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3076                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3077                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3078                 return TRUE;
3079         }
3080
3081         destreg = iargs [0]->dreg;
3082         srcreg = iargs [1]->dreg;
3083         offset = 0;
3084
3085         dest_ptr_reg = alloc_preg (cfg);
3086         tmp_reg = alloc_preg (cfg);
3087
3088         /*tmp = dreg*/
3089         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3090
3091         while (size >= SIZEOF_VOID_P) {
3092                 MonoInst *load_inst;
3093                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3094                 load_inst->dreg = tmp_reg;
3095                 load_inst->inst_basereg = srcreg;
3096                 load_inst->inst_offset = offset;
3097                 MONO_ADD_INS (cfg->cbb, load_inst);
3098
3099                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3100
3101                 if (need_wb & 0x1)
3102                         emit_write_barrier (cfg, iargs [0], load_inst);
3103
3104                 offset += SIZEOF_VOID_P;
3105                 size -= SIZEOF_VOID_P;
3106                 need_wb >>= 1;
3107
3108                 /*tmp += sizeof (void*)*/
3109                 if (size >= SIZEOF_VOID_P) {
3110                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3111                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3112                 }
3113         }
3114
3115         /* Those cannot be references since size < sizeof (void*) */
3116         while (size >= 4) {
3117                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3118                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3119                 offset += 4;
3120                 size -= 4;
3121         }
3122
3123         while (size >= 2) {
3124                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3125                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3126                 offset += 2;
3127                 size -= 2;
3128         }
3129
3130         while (size >= 1) {
3131                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3132                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3133                 offset += 1;
3134                 size -= 1;
3135         }
3136
3137         return TRUE;
3138 }
3139
3140 /*
3141  * Emit code to copy a valuetype of type @klass whose address is stored in
3142  * @src->dreg to memory whose address is stored at @dest->dreg.
3143  */
3144 void
3145 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3146 {
3147         MonoInst *iargs [4];
3148         int n;
3149         guint32 align = 0;
3150         MonoMethod *memcpy_method;
3151         MonoInst *size_ins = NULL;
3152         MonoInst *memcpy_ins = NULL;
3153
3154         g_assert (klass);
3155         if (cfg->gshared)
3156                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3157
3158         /*
3159          * This check breaks with spilled vars... need to handle it during verification anyway.
3160          * g_assert (klass && klass == src->klass && klass == dest->klass);
3161          */
3162
3163         if (mini_is_gsharedvt_klass (klass)) {
3164                 g_assert (!native);
3165                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3166                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3167         }
3168
3169         if (native)
3170                 n = mono_class_native_size (klass, &align);
3171         else
3172                 n = mono_class_value_size (klass, &align);
3173
3174         /* if native is true there should be no references in the struct */
3175         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3176                 /* Avoid barriers when storing to the stack */
3177                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3178                           (dest->opcode == OP_LDADDR))) {
3179                         int context_used;
3180
3181                         iargs [0] = dest;
3182                         iargs [1] = src;
3183
3184                         context_used = mini_class_check_context_used (cfg, klass);
3185
3186                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3187                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3188                                 return;
3189                         } else if (context_used) {
3190                                 iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3191                         }  else {
3192                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3193                                 if (!cfg->compile_aot)
3194                                         mono_class_compute_gc_descriptor (klass);
3195                         }
3196
3197                         if (size_ins)
3198                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3199                         else
3200                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3201                         return;
3202                 }
3203         }
3204
3205         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3206                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3207                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3208         } else {
3209                 iargs [0] = dest;
3210                 iargs [1] = src;
3211                 if (size_ins)
3212                         iargs [2] = size_ins;
3213                 else
3214                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3215                 
3216                 memcpy_method = get_memcpy_method ();
3217                 if (memcpy_ins)
3218                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3219                 else
3220                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3221         }
3222 }
3223
3224 static MonoMethod*
3225 get_memset_method (void)
3226 {
3227         static MonoMethod *memset_method = NULL;
3228         if (!memset_method) {
3229                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3230                 if (!memset_method)
3231                         g_error ("Old corlib found. Install a new one");
3232         }
3233         return memset_method;
3234 }
3235
3236 void
3237 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3238 {
3239         MonoInst *iargs [3];
3240         int n;
3241         guint32 align;
3242         MonoMethod *memset_method;
3243         MonoInst *size_ins = NULL;
3244         MonoInst *bzero_ins = NULL;
3245         static MonoMethod *bzero_method;
3246
3247         /* FIXME: Optimize this for the case when dest is an LDADDR */
3248         mono_class_init (klass);
3249         if (mini_is_gsharedvt_klass (klass)) {
3250                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3251                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3252                 if (!bzero_method)
3253                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3254                 g_assert (bzero_method);
3255                 iargs [0] = dest;
3256                 iargs [1] = size_ins;
3257                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3258                 return;
3259         }
3260
3261         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3262
3263         n = mono_class_value_size (klass, &align);
3264
3265         if (n <= sizeof (gpointer) * 8) {
3266                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3267         }
3268         else {
3269                 memset_method = get_memset_method ();
3270                 iargs [0] = dest;
3271                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3272                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3273                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3274         }
3275 }
3276
3277 /*
3278  * emit_get_rgctx:
3279  *
3280  *   Emit IR to return either the this pointer for instance method,
3281  * or the mrgctx for static methods.
3282  */
3283 static MonoInst*
3284 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3285 {
3286         MonoInst *this_ins = NULL;
3287
3288         g_assert (cfg->gshared);
3289
3290         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3291                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3292                 !method->klass->valuetype)
3293                 EMIT_NEW_VARLOAD (cfg, this_ins, cfg->this_arg, &mono_defaults.object_class->byval_arg);
3294
3295         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3296                 MonoInst *mrgctx_loc, *mrgctx_var;
3297
3298                 g_assert (!this_ins);
3299                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3300
3301                 mrgctx_loc = mono_get_vtable_var (cfg);
3302                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3303
3304                 return mrgctx_var;
3305         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3306                 MonoInst *vtable_loc, *vtable_var;
3307
3308                 g_assert (!this_ins);
3309
3310                 vtable_loc = mono_get_vtable_var (cfg);
3311                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3312
3313                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3314                         MonoInst *mrgctx_var = vtable_var;
3315                         int vtable_reg;
3316
3317                         vtable_reg = alloc_preg (cfg);
3318                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3319                         vtable_var->type = STACK_PTR;
3320                 }
3321
3322                 return vtable_var;
3323         } else {
3324                 MonoInst *ins;
3325                 int vtable_reg;
3326         
3327                 vtable_reg = alloc_preg (cfg);
3328                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3329                 return ins;
3330         }
3331 }
3332
3333 static MonoJumpInfoRgctxEntry *
3334 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3335 {
3336         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3337         res->method = method;
3338         res->in_mrgctx = in_mrgctx;
3339         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3340         res->data->type = patch_type;
3341         res->data->data.target = patch_data;
3342         res->info_type = info_type;
3343
3344         return res;
3345 }
3346
3347 static inline MonoInst*
3348 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3349 {
3350         MonoInst *args [16];
3351         MonoInst *call;
3352
3353         // FIXME: No fastpath since the slot is not a compile time constant
3354         args [0] = rgctx;
3355         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3356         if (entry->in_mrgctx)
3357                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3358         else
3359                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3360         return call;
3361 #if 0
3362         /*
3363          * FIXME: This can be called during decompose, which is a problem since it creates
3364          * new bblocks.
3365          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3366          */
3367         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3368         gboolean mrgctx;
3369         MonoBasicBlock *is_null_bb, *end_bb;
3370         MonoInst *res, *ins, *call;
3371         MonoInst *args[16];
3372
3373         slot = mini_get_rgctx_entry_slot (entry);
3374
3375         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3376         index = MONO_RGCTX_SLOT_INDEX (slot);
3377         if (mrgctx)
3378                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3379         for (depth = 0; ; ++depth) {
3380                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3381
3382                 if (index < size - 1)
3383                         break;
3384                 index -= size - 1;
3385         }
3386
3387         NEW_BBLOCK (cfg, end_bb);
3388         NEW_BBLOCK (cfg, is_null_bb);
3389
3390         if (mrgctx) {
3391                 rgctx_reg = rgctx->dreg;
3392         } else {
3393                 rgctx_reg = alloc_preg (cfg);
3394
3395                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3396                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3397                 NEW_BBLOCK (cfg, is_null_bb);
3398
3399                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3400                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3401         }
3402
3403         for (i = 0; i < depth; ++i) {
3404                 int array_reg = alloc_preg (cfg);
3405
3406                 /* load ptr to next array */
3407                 if (mrgctx && i == 0)
3408                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3409                 else
3410                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3411                 rgctx_reg = array_reg;
3412                 /* is the ptr null? */
3413                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3414                 /* if yes, jump to actual trampoline */
3415                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3416         }
3417
3418         /* fetch slot */
3419         val_reg = alloc_preg (cfg);
3420         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3421         /* is the slot null? */
3422         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3423         /* if yes, jump to actual trampoline */
3424         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3425
3426         /* Fastpath */
3427         res_reg = alloc_preg (cfg);
3428         MONO_INST_NEW (cfg, ins, OP_MOVE);
3429         ins->dreg = res_reg;
3430         ins->sreg1 = val_reg;
3431         MONO_ADD_INS (cfg->cbb, ins);
3432         res = ins;
3433         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3434
3435         /* Slowpath */
3436         MONO_START_BB (cfg, is_null_bb);
3437         args [0] = rgctx;
3438         EMIT_NEW_ICONST (cfg, args [1], index);
3439         if (mrgctx)
3440                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3441         else
3442                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3443         MONO_INST_NEW (cfg, ins, OP_MOVE);
3444         ins->dreg = res_reg;
3445         ins->sreg1 = call->dreg;
3446         MONO_ADD_INS (cfg->cbb, ins);
3447         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3448
3449         MONO_START_BB (cfg, end_bb);
3450
3451         return res;
3452 #endif
3453 }
3454
3455 /*
3456  * emit_rgctx_fetch:
3457  *
3458  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3459  * given by RGCTX.
3460  */
3461 static inline MonoInst*
3462 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3463 {
3464         if (cfg->llvm_only)
3465                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3466         else
3467                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3468 }
3469
3470 MonoInst*
3471 mini_emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3472                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3473 {
3474         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);
3475         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3476
3477         return emit_rgctx_fetch (cfg, rgctx, entry);
3478 }
3479
3480 static MonoInst*
3481 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3482                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3483 {
3484         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);
3485         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3486
3487         return emit_rgctx_fetch (cfg, rgctx, entry);
3488 }
3489
3490 static MonoInst*
3491 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3492                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3493 {
3494         MonoJumpInfoGSharedVtCall *call_info;
3495         MonoJumpInfoRgctxEntry *entry;
3496         MonoInst *rgctx;
3497
3498         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3499         call_info->sig = sig;
3500         call_info->method = cmethod;
3501
3502         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);
3503         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3504
3505         return emit_rgctx_fetch (cfg, rgctx, entry);
3506 }
3507
3508 /*
3509  * emit_get_rgctx_virt_method:
3510  *
3511  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3512  */
3513 static MonoInst*
3514 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3515                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3516 {
3517         MonoJumpInfoVirtMethod *info;
3518         MonoJumpInfoRgctxEntry *entry;
3519         MonoInst *rgctx;
3520
3521         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3522         info->klass = klass;
3523         info->method = virt_method;
3524
3525         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);
3526         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3527
3528         return emit_rgctx_fetch (cfg, rgctx, entry);
3529 }
3530
3531 static MonoInst*
3532 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3533                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3534 {
3535         MonoJumpInfoRgctxEntry *entry;
3536         MonoInst *rgctx;
3537
3538         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);
3539         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3540
3541         return emit_rgctx_fetch (cfg, rgctx, entry);
3542 }
3543
3544 /*
3545  * emit_get_rgctx_method:
3546  *
3547  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3548  * normal constants, else emit a load from the rgctx.
3549  */
3550 static MonoInst*
3551 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3552                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3553 {
3554         if (!context_used) {
3555                 MonoInst *ins;
3556
3557                 switch (rgctx_type) {
3558                 case MONO_RGCTX_INFO_METHOD:
3559                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3560                         return ins;
3561                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3562                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3563                         return ins;
3564                 default:
3565                         g_assert_not_reached ();
3566                 }
3567         } else {
3568                 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);
3569                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3570
3571                 return emit_rgctx_fetch (cfg, rgctx, entry);
3572         }
3573 }
3574
3575 static MonoInst*
3576 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3577                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3578 {
3579         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);
3580         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3581
3582         return emit_rgctx_fetch (cfg, rgctx, entry);
3583 }
3584
3585 static int
3586 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3587 {
3588         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3589         MonoRuntimeGenericContextInfoTemplate *template_;
3590         int i, idx;
3591
3592         g_assert (info);
3593
3594         for (i = 0; i < info->num_entries; ++i) {
3595                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3596
3597                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3598                         return i;
3599         }
3600
3601         if (info->num_entries == info->count_entries) {
3602                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3603                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3604
3605                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3606
3607                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3608                 info->entries = new_entries;
3609                 info->count_entries = new_count_entries;
3610         }
3611
3612         idx = info->num_entries;
3613         template_ = &info->entries [idx];
3614         template_->info_type = rgctx_type;
3615         template_->data = data;
3616
3617         info->num_entries ++;
3618
3619         return idx;
3620 }
3621
3622 /*
3623  * emit_get_gsharedvt_info:
3624  *
3625  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3626  */
3627 static MonoInst*
3628 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3629 {
3630         MonoInst *ins;
3631         int idx, dreg;
3632
3633         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3634         /* Load info->entries [idx] */
3635         dreg = alloc_preg (cfg);
3636         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3637
3638         return ins;
3639 }
3640
3641 static MonoInst*
3642 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3643 {
3644         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3645 }
3646
3647 /*
3648  * On return the caller must check @klass for load errors.
3649  */
3650 static void
3651 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3652 {
3653         MonoInst *vtable_arg;
3654         int context_used;
3655
3656         context_used = mini_class_check_context_used (cfg, klass);
3657
3658         if (context_used) {
3659                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
3660                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3661         } else {
3662                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3663
3664                 if (!vtable)
3665                         return;
3666                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3667         }
3668
3669         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3670                 MonoInst *ins;
3671
3672                 /*
3673                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3674                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3675                  */
3676                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3677                 ins->sreg1 = vtable_arg->dreg;
3678                 MONO_ADD_INS (cfg->cbb, ins);
3679         } else {
3680                 int inited_reg;
3681                 MonoBasicBlock *inited_bb;
3682                 MonoInst *args [16];
3683
3684                 inited_reg = alloc_ireg (cfg);
3685
3686                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, inited_reg, vtable_arg->dreg, MONO_STRUCT_OFFSET (MonoVTable, initialized));
3687
3688                 NEW_BBLOCK (cfg, inited_bb);
3689
3690                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3691                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3692
3693                 args [0] = vtable_arg;
3694                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3695
3696                 MONO_START_BB (cfg, inited_bb);
3697         }
3698 }
3699
3700 static void
3701 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3702 {
3703         MonoInst *ins;
3704
3705         if (cfg->gen_seq_points && cfg->method == method) {
3706                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3707                 if (nonempty_stack)
3708                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3709                 MONO_ADD_INS (cfg->cbb, ins);
3710         }
3711 }
3712
3713 void
3714 mini_save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3715 {
3716         if (mini_get_debug_options ()->better_cast_details) {
3717                 int vtable_reg = alloc_preg (cfg);
3718                 int klass_reg = alloc_preg (cfg);
3719                 MonoBasicBlock *is_null_bb = NULL;
3720                 MonoInst *tls_get;
3721                 int to_klass_reg, context_used;
3722
3723                 if (null_check) {
3724                         NEW_BBLOCK (cfg, is_null_bb);
3725
3726                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3727                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3728                 }
3729
3730                 tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
3731                 if (!tls_get) {
3732                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3733                         exit (1);
3734                 }
3735
3736                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3737                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3738
3739                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3740
3741                 context_used = mini_class_check_context_used (cfg, klass);
3742                 if (context_used) {
3743                         MonoInst *class_ins;
3744
3745                         class_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3746                         to_klass_reg = class_ins->dreg;
3747                 } else {
3748                         to_klass_reg = alloc_preg (cfg);
3749                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3750                 }
3751                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3752
3753                 if (null_check)
3754                         MONO_START_BB (cfg, is_null_bb);
3755         }
3756 }
3757
3758 void
3759 mini_reset_cast_details (MonoCompile *cfg)
3760 {
3761         /* Reset the variables holding the cast details */
3762         if (mini_get_debug_options ()->better_cast_details) {
3763                 MonoInst *tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
3764                 /* It is enough to reset the from field */
3765                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3766         }
3767 }
3768
3769 /*
3770  * On return the caller must check @array_class for load errors
3771  */
3772 static void
3773 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3774 {
3775         int vtable_reg = alloc_preg (cfg);
3776         int context_used;
3777
3778         context_used = mini_class_check_context_used (cfg, array_class);
3779
3780         mini_save_cast_details (cfg, array_class, obj->dreg, FALSE);
3781
3782         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3783
3784         if (cfg->opt & MONO_OPT_SHARED) {
3785                 int class_reg = alloc_preg (cfg);
3786                 MonoInst *ins;
3787
3788                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3789                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3790                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3791         } else if (context_used) {
3792                 MonoInst *vtable_ins;
3793
3794                 vtable_ins = mini_emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3795                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3796         } else {
3797                 if (cfg->compile_aot) {
3798                         int vt_reg;
3799                         MonoVTable *vtable;
3800
3801                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3802                                 return;
3803                         vt_reg = alloc_preg (cfg);
3804                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3805                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3806                 } else {
3807                         MonoVTable *vtable;
3808                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3809                                 return;
3810                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3811                 }
3812         }
3813         
3814         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3815
3816         mini_reset_cast_details (cfg);
3817 }
3818
3819 /**
3820  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3821  * generic code is generated.
3822  */
3823 static MonoInst*
3824 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3825 {
3826         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3827
3828         if (context_used) {
3829                 MonoInst *rgctx, *addr;
3830
3831                 /* FIXME: What if the class is shared?  We might not
3832                    have to get the address of the method from the
3833                    RGCTX. */
3834                 addr = emit_get_rgctx_method (cfg, context_used, method,
3835                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3836                 if (cfg->llvm_only) {
3837                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
3838                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
3839                 } else {
3840                         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3841
3842                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3843                 }
3844         } else {
3845                 gboolean pass_vtable, pass_mrgctx;
3846                 MonoInst *rgctx_arg = NULL;
3847
3848                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3849                 g_assert (!pass_mrgctx);
3850
3851                 if (pass_vtable) {
3852                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3853
3854                         g_assert (vtable);
3855                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3856                 }
3857
3858                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3859         }
3860 }
3861
3862 static MonoInst*
3863 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3864 {
3865         MonoInst *add;
3866         int obj_reg;
3867         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3868         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3869         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3870         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3871
3872         obj_reg = sp [0]->dreg;
3873         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3874         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3875
3876         /* FIXME: generics */
3877         g_assert (klass->rank == 0);
3878                         
3879         // Check rank == 0
3880         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3881         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3882
3883         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3884         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3885
3886         if (context_used) {
3887                 MonoInst *element_class;
3888
3889                 /* This assertion is from the unboxcast insn */
3890                 g_assert (klass->rank == 0);
3891
3892                 element_class = mini_emit_get_rgctx_klass (cfg, context_used,
3893                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
3894
3895                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3896                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3897         } else {
3898                 mini_save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
3899                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3900                 mini_reset_cast_details (cfg);
3901         }
3902
3903         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3904         MONO_ADD_INS (cfg->cbb, add);
3905         add->type = STACK_MP;
3906         add->klass = klass;
3907
3908         return add;
3909 }
3910
3911 static MonoInst*
3912 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
3913 {
3914         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3915         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3916         MonoInst *ins;
3917         int dreg, addr_reg;
3918
3919         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3920
3921         /* obj */
3922         args [0] = obj;
3923
3924         /* klass */
3925         args [1] = klass_inst;
3926
3927         /* CASTCLASS */
3928         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3929
3930         NEW_BBLOCK (cfg, is_ref_bb);
3931         NEW_BBLOCK (cfg, is_nullable_bb);
3932         NEW_BBLOCK (cfg, end_bb);
3933         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3934         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
3935         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3936
3937         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
3938         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3939
3940         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3941         addr_reg = alloc_dreg (cfg, STACK_MP);
3942
3943         /* Non-ref case */
3944         /* UNBOX */
3945         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3946         MONO_ADD_INS (cfg->cbb, addr);
3947
3948         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3949
3950         /* Ref case */
3951         MONO_START_BB (cfg, is_ref_bb);
3952
3953         /* Save the ref to a temporary */
3954         dreg = alloc_ireg (cfg);
3955         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3956         addr->dreg = addr_reg;
3957         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3958         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3959
3960         /* Nullable case */
3961         MONO_START_BB (cfg, is_nullable_bb);
3962
3963         {
3964                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3965                 MonoInst *unbox_call;
3966                 MonoMethodSignature *unbox_sig;
3967
3968                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3969                 unbox_sig->ret = &klass->byval_arg;
3970                 unbox_sig->param_count = 1;
3971                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3972
3973                 if (cfg->llvm_only)
3974                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
3975                 else
3976                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3977
3978                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3979                 addr->dreg = addr_reg;
3980         }
3981
3982         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3983
3984         /* End */
3985         MONO_START_BB (cfg, end_bb);
3986
3987         /* LDOBJ */
3988         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3989
3990         return ins;
3991 }
3992
3993 /*
3994  * Returns NULL and set the cfg exception on error.
3995  */
3996 static MonoInst*
3997 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3998 {
3999         MonoInst *iargs [2];
4000         void *alloc_ftn;
4001
4002         if (context_used) {
4003                 MonoInst *data;
4004                 MonoRgctxInfoType rgctx_info;
4005                 MonoInst *iargs [2];
4006                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4007
4008                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4009
4010                 if (cfg->opt & MONO_OPT_SHARED)
4011                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4012                 else
4013                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4014                 data = mini_emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4015
4016                 if (cfg->opt & MONO_OPT_SHARED) {
4017                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4018                         iargs [1] = data;
4019                         alloc_ftn = ves_icall_object_new;
4020                 } else {
4021                         iargs [0] = data;
4022                         alloc_ftn = ves_icall_object_new_specific;
4023                 }
4024
4025                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4026                         if (known_instance_size) {
4027                                 int size = mono_class_instance_size (klass);
4028                                 if (size < sizeof (MonoObject))
4029                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4030
4031                                 EMIT_NEW_ICONST (cfg, iargs [1], size);
4032                         }
4033                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4034                 }
4035
4036                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4037         }
4038
4039         if (cfg->opt & MONO_OPT_SHARED) {
4040                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4041                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4042
4043                 alloc_ftn = ves_icall_object_new;
4044         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !mono_class_is_ginst (klass)) {
4045                 /* This happens often in argument checking code, eg. throw new FooException... */
4046                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4047                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4048                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4049         } else {
4050                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4051                 MonoMethod *managed_alloc = NULL;
4052                 gboolean pass_lw;
4053
4054                 if (!vtable) {
4055                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4056                         cfg->exception_ptr = klass;
4057                         return NULL;
4058                 }
4059
4060                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4061
4062                 if (managed_alloc) {
4063                         int size = mono_class_instance_size (klass);
4064                         if (size < sizeof (MonoObject))
4065                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4066
4067                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4068                         EMIT_NEW_ICONST (cfg, iargs [1], size);
4069                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4070                 }
4071                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4072                 if (pass_lw) {
4073                         guint32 lw = vtable->klass->instance_size;
4074                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4075                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4076                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4077                 }
4078                 else {
4079                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4080                 }
4081         }
4082
4083         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4084 }
4085         
4086 /*
4087  * Returns NULL and set the cfg exception on error.
4088  */     
4089 static MonoInst*
4090 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4091 {
4092         MonoInst *alloc, *ins;
4093
4094         if (mono_class_is_nullable (klass)) {
4095                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4096
4097                 if (context_used) {
4098                         if (cfg->llvm_only && cfg->gsharedvt) {
4099                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4100                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4101                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4102                         } else {
4103                                 /* FIXME: What if the class is shared?  We might not
4104                                    have to get the method address from the RGCTX. */
4105                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4106                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4107                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
4108
4109                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4110                         }
4111                 } else {
4112                         gboolean pass_vtable, pass_mrgctx;
4113                         MonoInst *rgctx_arg = NULL;
4114
4115                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4116                         g_assert (!pass_mrgctx);
4117
4118                         if (pass_vtable) {
4119                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4120
4121                                 g_assert (vtable);
4122                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4123                         }
4124
4125                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4126                 }
4127         }
4128
4129         if (mini_is_gsharedvt_klass (klass)) {
4130                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4131                 MonoInst *res, *is_ref, *src_var, *addr;
4132                 int dreg;
4133
4134                 dreg = alloc_ireg (cfg);
4135
4136                 NEW_BBLOCK (cfg, is_ref_bb);
4137                 NEW_BBLOCK (cfg, is_nullable_bb);
4138                 NEW_BBLOCK (cfg, end_bb);
4139                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4140                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4141                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4142
4143                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4144                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4145
4146                 /* Non-ref case */
4147                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4148                 if (!alloc)
4149                         return NULL;
4150                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4151                 ins->opcode = OP_STOREV_MEMBASE;
4152
4153                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4154                 res->type = STACK_OBJ;
4155                 res->klass = klass;
4156                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4157                 
4158                 /* Ref case */
4159                 MONO_START_BB (cfg, is_ref_bb);
4160
4161                 /* val is a vtype, so has to load the value manually */
4162                 src_var = get_vreg_to_inst (cfg, val->dreg);
4163                 if (!src_var)
4164                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4165                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4166                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4167                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4168
4169                 /* Nullable case */
4170                 MONO_START_BB (cfg, is_nullable_bb);
4171
4172                 {
4173                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4174                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4175                         MonoInst *box_call;
4176                         MonoMethodSignature *box_sig;
4177
4178                         /*
4179                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4180                          * construct that method at JIT time, so have to do things by hand.
4181                          */
4182                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4183                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4184                         box_sig->param_count = 1;
4185                         box_sig->params [0] = &klass->byval_arg;
4186
4187                         if (cfg->llvm_only)
4188                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4189                         else
4190                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4191                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4192                         res->type = STACK_OBJ;
4193                         res->klass = klass;
4194                 }
4195
4196                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4197
4198                 MONO_START_BB (cfg, end_bb);
4199
4200                 return res;
4201         } else {
4202                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4203                 if (!alloc)
4204                         return NULL;
4205
4206                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4207                 return alloc;
4208         }
4209 }
4210
4211 static GHashTable* direct_icall_type_hash;
4212
4213 static gboolean
4214 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4215 {
4216         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4217         if (!direct_icalls_enabled (cfg))
4218                 return FALSE;
4219
4220         /*
4221          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4222          * Whitelist a few icalls for now.
4223          */
4224         if (!direct_icall_type_hash) {
4225                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4226
4227                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4228                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4229                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4230                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4231                 mono_memory_barrier ();
4232                 direct_icall_type_hash = h;
4233         }
4234
4235         if (cmethod->klass == mono_defaults.math_class)
4236                 return TRUE;
4237         /* No locking needed */
4238         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4239                 return TRUE;
4240         return FALSE;
4241 }
4242
4243 static gboolean
4244 method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
4245 {
4246         if (cmethod->klass == mono_defaults.systemtype_class) {
4247                 if (!strcmp (cmethod->name, "GetType"))
4248                         return TRUE;
4249         }
4250         return FALSE;
4251 }
4252
4253 static G_GNUC_UNUSED MonoInst*
4254 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4255 {
4256         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4257         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4258         gboolean is_i4;
4259
4260         switch (enum_type->type) {
4261         case MONO_TYPE_I8:
4262         case MONO_TYPE_U8:
4263 #if SIZEOF_REGISTER == 8
4264         case MONO_TYPE_I:
4265         case MONO_TYPE_U:
4266 #endif
4267                 is_i4 = FALSE;
4268                 break;
4269         default:
4270                 is_i4 = TRUE;
4271                 break;
4272         }
4273
4274         {
4275                 MonoInst *load, *and_, *cmp, *ceq;
4276                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4277                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4278                 int dest_reg = alloc_ireg (cfg);
4279
4280                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4281                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4282                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4283                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4284
4285                 ceq->type = STACK_I4;
4286
4287                 if (!is_i4) {
4288                         load = mono_decompose_opcode (cfg, load);
4289                         and_ = mono_decompose_opcode (cfg, and_);
4290                         cmp = mono_decompose_opcode (cfg, cmp);
4291                         ceq = mono_decompose_opcode (cfg, ceq);
4292                 }
4293
4294                 return ceq;
4295         }
4296 }
4297
4298 /*
4299  * Returns NULL and set the cfg exception on error.
4300  */
4301 static G_GNUC_UNUSED MonoInst*
4302 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
4303 {
4304         MonoInst *ptr;
4305         int dreg;
4306         gpointer trampoline;
4307         MonoInst *obj, *method_ins, *tramp_ins;
4308         MonoDomain *domain;
4309         guint8 **code_slot;
4310
4311         if (virtual_ && !cfg->llvm_only) {
4312                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4313                 g_assert (invoke);
4314
4315                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4316                         return NULL;
4317         }
4318
4319         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
4320         if (!obj)
4321                 return NULL;
4322
4323         /* Inline the contents of mono_delegate_ctor */
4324
4325         /* Set target field */
4326         /* Optimize away setting of NULL target */
4327         if (!MONO_INS_IS_PCONST_NULL (target)) {
4328                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4329                 if (cfg->gen_write_barriers) {
4330                         dreg = alloc_preg (cfg);
4331                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4332                         emit_write_barrier (cfg, ptr, target);
4333                 }
4334         }
4335
4336         /* Set method field */
4337         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4338         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4339
4340         /* 
4341          * To avoid looking up the compiled code belonging to the target method
4342          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4343          * store it, and we fill it after the method has been compiled.
4344          */
4345         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4346                 MonoInst *code_slot_ins;
4347
4348                 if (context_used) {
4349                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4350                 } else {
4351                         domain = mono_domain_get ();
4352                         mono_domain_lock (domain);
4353                         if (!domain_jit_info (domain)->method_code_hash)
4354                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4355                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4356                         if (!code_slot) {
4357                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
4358                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4359                         }
4360                         mono_domain_unlock (domain);
4361
4362                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4363                 }
4364                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4365         }
4366
4367         if (cfg->llvm_only) {
4368                 MonoInst *args [16];
4369
4370                 if (virtual_) {
4371                         args [0] = obj;
4372                         args [1] = target;
4373                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4374                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
4375                 } else {
4376                         args [0] = obj;
4377                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
4378                 }
4379
4380                 return obj;
4381         }
4382
4383         if (cfg->compile_aot) {
4384                 MonoDelegateClassMethodPair *del_tramp;
4385
4386                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4387                 del_tramp->klass = klass;
4388                 del_tramp->method = context_used ? NULL : method;
4389                 del_tramp->is_virtual = virtual_;
4390                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4391         } else {
4392                 if (virtual_)
4393                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4394                 else
4395                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4396                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4397         }
4398
4399         /* Set invoke_impl field */
4400         if (virtual_) {
4401                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4402         } else {
4403                 dreg = alloc_preg (cfg);
4404                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4405                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4406
4407                 dreg = alloc_preg (cfg);
4408                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4409                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4410         }
4411
4412         dreg = alloc_preg (cfg);
4413         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
4414         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
4415
4416         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4417
4418         return obj;
4419 }
4420
4421 static MonoInst*
4422 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4423 {
4424         MonoJitICallInfo *info;
4425
4426         /* Need to register the icall so it gets an icall wrapper */
4427         info = mono_get_array_new_va_icall (rank);
4428
4429         cfg->flags |= MONO_CFG_HAS_VARARGS;
4430
4431         /* mono_array_new_va () needs a vararg calling convention */
4432         cfg->exception_message = g_strdup ("array-new");
4433         cfg->disable_llvm = TRUE;
4434
4435         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4436         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4437 }
4438
4439 /*
4440  * handle_constrained_gsharedvt_call:
4441  *
4442  *   Handle constrained calls where the receiver is a gsharedvt type.
4443  * Return the instruction representing the call. Set the cfg exception on failure.
4444  */
4445 static MonoInst*
4446 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
4447                                                                    gboolean *ref_emit_widen)
4448 {
4449         MonoInst *ins = NULL;
4450         gboolean emit_widen = *ref_emit_widen;
4451
4452         /*
4453          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
4454          * 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
4455          * pack the arguments into an array, and do the rest of the work in in an icall.
4456          */
4457         if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
4458                 (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)) &&
4459                 (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]))))) {
4460                 MonoInst *args [16];
4461
4462                 /*
4463                  * This case handles calls to
4464                  * - object:ToString()/Equals()/GetHashCode(),
4465                  * - System.IComparable<T>:CompareTo()
4466                  * - System.IEquatable<T>:Equals ()
4467                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
4468                  */
4469
4470                 args [0] = sp [0];
4471                 if (mono_method_check_context_used (cmethod))
4472                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
4473                 else
4474                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
4475                 args [2] = mini_emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
4476
4477                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
4478                 if (fsig->hasthis && fsig->param_count) {
4479                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
4480                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
4481                         ins->dreg = alloc_preg (cfg);
4482                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
4483                         MONO_ADD_INS (cfg->cbb, ins);
4484                         args [4] = ins;
4485
4486                         if (mini_is_gsharedvt_type (fsig->params [0])) {
4487                                 int addr_reg, deref_arg_reg;
4488
4489                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4490                                 deref_arg_reg = alloc_preg (cfg);
4491                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
4492                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
4493
4494                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
4495                                 addr_reg = ins->dreg;
4496                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
4497                         } else {
4498                                 EMIT_NEW_ICONST (cfg, args [3], 0);
4499                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
4500                         }
4501                 } else {
4502                         EMIT_NEW_ICONST (cfg, args [3], 0);
4503                         EMIT_NEW_ICONST (cfg, args [4], 0);
4504                 }
4505                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
4506                 emit_widen = FALSE;
4507
4508                 if (mini_is_gsharedvt_type (fsig->ret)) {
4509                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
4510                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mono_class_is_enum (mono_class_from_mono_type (fsig->ret))) {
4511                         MonoInst *add;
4512
4513                         /* Unbox */
4514                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
4515                         MONO_ADD_INS (cfg->cbb, add);
4516                         /* Load value */
4517                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
4518                         MONO_ADD_INS (cfg->cbb, ins);
4519                         /* ins represents the call result */
4520                 }
4521         } else {
4522                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
4523         }
4524
4525         *ref_emit_widen = emit_widen;
4526
4527         return ins;
4528
4529  exception_exit:
4530         return NULL;
4531 }
4532
4533 static void
4534 mono_emit_load_got_addr (MonoCompile *cfg)
4535 {
4536         MonoInst *getaddr, *dummy_use;
4537
4538         if (!cfg->got_var || cfg->got_var_allocated)
4539                 return;
4540
4541         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4542         getaddr->cil_code = cfg->header->code;
4543         getaddr->dreg = cfg->got_var->dreg;
4544
4545         /* Add it to the start of the first bblock */
4546         if (cfg->bb_entry->code) {
4547                 getaddr->next = cfg->bb_entry->code;
4548                 cfg->bb_entry->code = getaddr;
4549         }
4550         else
4551                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4552
4553         cfg->got_var_allocated = TRUE;
4554
4555         /* 
4556          * Add a dummy use to keep the got_var alive, since real uses might
4557          * only be generated by the back ends.
4558          * Add it to end_bblock, so the variable's lifetime covers the whole
4559          * method.
4560          * It would be better to make the usage of the got var explicit in all
4561          * cases when the backend needs it (i.e. calls, throw etc.), so this
4562          * wouldn't be needed.
4563          */
4564         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4565         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4566 }
4567
4568 static int inline_limit;
4569 static gboolean inline_limit_inited;
4570
4571 static gboolean
4572 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4573 {
4574         MonoMethodHeaderSummary header;
4575         MonoVTable *vtable;
4576 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4577         MonoMethodSignature *sig = mono_method_signature (method);
4578         int i;
4579 #endif
4580
4581         if (cfg->disable_inline)
4582                 return FALSE;
4583         if (cfg->gsharedvt)
4584                 return FALSE;
4585
4586         if (cfg->inline_depth > 10)
4587                 return FALSE;
4588
4589         if (!mono_method_get_header_summary (method, &header))
4590                 return FALSE;
4591
4592         /*runtime, icall and pinvoke are checked by summary call*/
4593         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4594             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4595             (mono_class_is_marshalbyref (method->klass)) ||
4596             header.has_clauses)
4597                 return FALSE;
4598
4599         /* also consider num_locals? */
4600         /* Do the size check early to avoid creating vtables */
4601         if (!inline_limit_inited) {
4602                 if (g_getenv ("MONO_INLINELIMIT"))
4603                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4604                 else
4605                         inline_limit = INLINE_LENGTH_LIMIT;
4606                 inline_limit_inited = TRUE;
4607         }
4608         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4609                 return FALSE;
4610
4611         /*
4612          * if we can initialize the class of the method right away, we do,
4613          * otherwise we don't allow inlining if the class needs initialization,
4614          * since it would mean inserting a call to mono_runtime_class_init()
4615          * inside the inlined code
4616          */
4617         if (cfg->gshared && method->klass->has_cctor && mini_class_check_context_used (cfg, method->klass))
4618                 return FALSE;
4619
4620         if (!(cfg->opt & MONO_OPT_SHARED)) {
4621                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4622                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4623                         if (method->klass->has_cctor) {
4624                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4625                                 if (!vtable)
4626                                         return FALSE;
4627                                 if (!cfg->compile_aot) {
4628                                         MonoError error;
4629                                         if (!mono_runtime_class_init_full (vtable, &error)) {
4630                                                 mono_error_cleanup (&error);
4631                                                 return FALSE;
4632                                         }
4633                                 }
4634                         }
4635                 } else if (mono_class_is_before_field_init (method->klass)) {
4636                         if (cfg->run_cctors && method->klass->has_cctor) {
4637                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4638                                 if (!method->klass->runtime_info)
4639                                         /* No vtable created yet */
4640                                         return FALSE;
4641                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4642                                 if (!vtable)
4643                                         return FALSE;
4644                                 /* This makes so that inline cannot trigger */
4645                                 /* .cctors: too many apps depend on them */
4646                                 /* running with a specific order... */
4647                                 if (! vtable->initialized)
4648                                         return FALSE;
4649                                 MonoError error;
4650                                 if (!mono_runtime_class_init_full (vtable, &error)) {
4651                                         mono_error_cleanup (&error);
4652                                         return FALSE;
4653                                 }
4654                         }
4655                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4656                         if (!method->klass->runtime_info)
4657                                 /* No vtable created yet */
4658                                 return FALSE;
4659                         vtable = mono_class_vtable (cfg->domain, method->klass);
4660                         if (!vtable)
4661                                 return FALSE;
4662                         if (!vtable->initialized)
4663                                 return FALSE;
4664                 }
4665         } else {
4666                 /* 
4667                  * If we're compiling for shared code
4668                  * the cctor will need to be run at aot method load time, for example,
4669                  * or at the end of the compilation of the inlining method.
4670                  */
4671                 if (mono_class_needs_cctor_run (method->klass, NULL) && !mono_class_is_before_field_init (method->klass))
4672                         return FALSE;
4673         }
4674
4675 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4676         if (mono_arch_is_soft_float ()) {
4677                 /* FIXME: */
4678                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4679                         return FALSE;
4680                 for (i = 0; i < sig->param_count; ++i)
4681                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4682                                 return FALSE;
4683         }
4684 #endif
4685
4686         if (g_list_find (cfg->dont_inline, method))
4687                 return FALSE;
4688
4689         return TRUE;
4690 }
4691
4692 static gboolean
4693 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4694 {
4695         if (!cfg->compile_aot) {
4696                 g_assert (vtable);
4697                 if (vtable->initialized)
4698                         return FALSE;
4699         }
4700
4701         if (mono_class_is_before_field_init (klass)) {
4702                 if (cfg->method == method)
4703                         return FALSE;
4704         }
4705
4706         if (!mono_class_needs_cctor_run (klass, method))
4707                 return FALSE;
4708
4709         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4710                 /* The initialization is already done before the method is called */
4711                 return FALSE;
4712
4713         return TRUE;
4714 }
4715
4716 MonoInst*
4717 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4718 {
4719         MonoInst *ins;
4720         guint32 size;
4721         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4722         int context_used;
4723
4724         if (mini_is_gsharedvt_variable_klass (klass)) {
4725                 size = -1;
4726         } else {
4727                 mono_class_init (klass);
4728                 size = mono_class_array_element_size (klass);
4729         }
4730
4731         mult_reg = alloc_preg (cfg);
4732         array_reg = arr->dreg;
4733         index_reg = index->dreg;
4734
4735 #if SIZEOF_REGISTER == 8
4736         /* The array reg is 64 bits but the index reg is only 32 */
4737         if (COMPILE_LLVM (cfg)) {
4738                 /* Not needed */
4739                 index2_reg = index_reg;
4740         } else {
4741                 index2_reg = alloc_preg (cfg);
4742                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4743         }
4744 #else
4745         if (index->type == STACK_I8) {
4746                 index2_reg = alloc_preg (cfg);
4747                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4748         } else {
4749                 index2_reg = index_reg;
4750         }
4751 #endif
4752
4753         if (bcheck)
4754                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4755
4756 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4757         if (size == 1 || size == 2 || size == 4 || size == 8) {
4758                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4759
4760                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
4761                 ins->klass = mono_class_get_element_class (klass);
4762                 ins->type = STACK_MP;
4763
4764                 return ins;
4765         }
4766 #endif          
4767
4768         add_reg = alloc_ireg_mp (cfg);
4769
4770         if (size == -1) {
4771                 MonoInst *rgctx_ins;
4772
4773                 /* gsharedvt */
4774                 g_assert (cfg->gshared);
4775                 context_used = mini_class_check_context_used (cfg, klass);
4776                 g_assert (context_used);
4777                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4778                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4779         } else {
4780                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4781         }
4782         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4783         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4784         ins->klass = mono_class_get_element_class (klass);
4785         ins->type = STACK_MP;
4786         MONO_ADD_INS (cfg->cbb, ins);
4787
4788         return ins;
4789 }
4790
4791 static MonoInst*
4792 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4793 {
4794         int bounds_reg = alloc_preg (cfg);
4795         int add_reg = alloc_ireg_mp (cfg);
4796         int mult_reg = alloc_preg (cfg);
4797         int mult2_reg = alloc_preg (cfg);
4798         int low1_reg = alloc_preg (cfg);
4799         int low2_reg = alloc_preg (cfg);
4800         int high1_reg = alloc_preg (cfg);
4801         int high2_reg = alloc_preg (cfg);
4802         int realidx1_reg = alloc_preg (cfg);
4803         int realidx2_reg = alloc_preg (cfg);
4804         int sum_reg = alloc_preg (cfg);
4805         int index1, index2, tmpreg;
4806         MonoInst *ins;
4807         guint32 size;
4808
4809         mono_class_init (klass);
4810         size = mono_class_array_element_size (klass);
4811
4812         index1 = index_ins1->dreg;
4813         index2 = index_ins2->dreg;
4814
4815 #if SIZEOF_REGISTER == 8
4816         /* The array reg is 64 bits but the index reg is only 32 */
4817         if (COMPILE_LLVM (cfg)) {
4818                 /* Not needed */
4819         } else {
4820                 tmpreg = alloc_preg (cfg);
4821                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4822                 index1 = tmpreg;
4823                 tmpreg = alloc_preg (cfg);
4824                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4825                 index2 = tmpreg;
4826         }
4827 #else
4828         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4829         tmpreg = -1;
4830 #endif
4831
4832         /* range checking */
4833         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4834                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4835
4836         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4837                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4838         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4839         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4840                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4841         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4842         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4843
4844         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4845                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4846         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4847         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4848                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4849         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4850         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4851
4852         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4853         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4854         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4855         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4856         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4857
4858         ins->type = STACK_MP;
4859         ins->klass = klass;
4860         MONO_ADD_INS (cfg->cbb, ins);
4861
4862         return ins;
4863 }
4864
4865 static MonoInst*
4866 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4867 {
4868         int rank;
4869         MonoInst *addr;
4870         MonoMethod *addr_method;
4871         int element_size;
4872         MonoClass *eclass = cmethod->klass->element_class;
4873
4874         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4875
4876         if (rank == 1)
4877                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
4878
4879         /* emit_ldelema_2 depends on OP_LMUL */
4880         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
4881                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
4882         }
4883
4884         if (mini_is_gsharedvt_variable_klass (eclass))
4885                 element_size = 0;
4886         else
4887                 element_size = mono_class_array_element_size (eclass);
4888         addr_method = mono_marshal_get_array_address (rank, element_size);
4889         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4890
4891         return addr;
4892 }
4893
4894 static MonoBreakPolicy
4895 always_insert_breakpoint (MonoMethod *method)
4896 {
4897         return MONO_BREAK_POLICY_ALWAYS;
4898 }
4899
4900 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4901
4902 /**
4903  * mono_set_break_policy:
4904  * policy_callback: the new callback function
4905  *
4906  * Allow embedders to decide wherther to actually obey breakpoint instructions
4907  * (both break IL instructions and Debugger.Break () method calls), for example
4908  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4909  * untrusted or semi-trusted code.
4910  *
4911  * @policy_callback will be called every time a break point instruction needs to
4912  * be inserted with the method argument being the method that calls Debugger.Break()
4913  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4914  * if it wants the breakpoint to not be effective in the given method.
4915  * #MONO_BREAK_POLICY_ALWAYS is the default.
4916  */
4917 void
4918 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4919 {
4920         if (policy_callback)
4921                 break_policy_func = policy_callback;
4922         else
4923                 break_policy_func = always_insert_breakpoint;
4924 }
4925
4926 static gboolean
4927 should_insert_brekpoint (MonoMethod *method) {
4928         switch (break_policy_func (method)) {
4929         case MONO_BREAK_POLICY_ALWAYS:
4930                 return TRUE;
4931         case MONO_BREAK_POLICY_NEVER:
4932                 return FALSE;
4933         case MONO_BREAK_POLICY_ON_DBG:
4934                 g_warning ("mdb no longer supported");
4935                 return FALSE;
4936         default:
4937                 g_warning ("Incorrect value returned from break policy callback");
4938                 return FALSE;
4939         }
4940 }
4941
4942 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4943 static MonoInst*
4944 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4945 {
4946         MonoInst *addr, *store, *load;
4947         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4948
4949         /* the bounds check is already done by the callers */
4950         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4951         if (is_set) {
4952                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4953                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4954                 if (mini_type_is_reference (&eklass->byval_arg))
4955                         emit_write_barrier (cfg, addr, load);
4956         } else {
4957                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4958                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4959         }
4960         return store;
4961 }
4962
4963
4964 static gboolean
4965 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4966 {
4967         return mini_type_is_reference (&klass->byval_arg);
4968 }
4969
4970 static MonoInst*
4971 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
4972 {
4973         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
4974                 !(MONO_INS_IS_PCONST_NULL (sp [2]))) {
4975                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
4976                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
4977                 MonoInst *iargs [3];
4978
4979                 if (!helper->slot)
4980                         mono_class_setup_vtable (obj_array);
4981                 g_assert (helper->slot);
4982
4983                 if (sp [0]->type != STACK_OBJ)
4984                         return NULL;
4985                 if (sp [2]->type != STACK_OBJ)
4986                         return NULL;
4987
4988                 iargs [2] = sp [2];
4989                 iargs [1] = sp [1];
4990                 iargs [0] = sp [0];
4991
4992                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
4993         } else {
4994                 MonoInst *ins;
4995
4996                 if (mini_is_gsharedvt_variable_klass (klass)) {
4997                         MonoInst *addr;
4998
4999                         // FIXME-VT: OP_ICONST optimization
5000                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5001                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5002                         ins->opcode = OP_STOREV_MEMBASE;
5003                 } else if (sp [1]->opcode == OP_ICONST) {
5004                         int array_reg = sp [0]->dreg;
5005                         int index_reg = sp [1]->dreg;
5006                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5007
5008                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5009                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5010
5011                         if (safety_checks)
5012                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5013                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5014                 } else {
5015                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5016                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5017                         if (generic_class_is_reference_type (cfg, klass))
5018                                 emit_write_barrier (cfg, addr, sp [2]);
5019                 }
5020                 return ins;
5021         }
5022 }
5023
5024 static MonoInst*
5025 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5026 {
5027         MonoClass *eklass;
5028         
5029         if (is_set)
5030                 eklass = mono_class_from_mono_type (fsig->params [2]);
5031         else
5032                 eklass = mono_class_from_mono_type (fsig->ret);
5033
5034         if (is_set) {
5035                 return emit_array_store (cfg, eklass, args, FALSE);
5036         } else {
5037                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5038                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5039                 return ins;
5040         }
5041 }
5042
5043 static gboolean
5044 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5045 {
5046         uint32_t align;
5047         int param_size, return_size;
5048
5049         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5050         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5051
5052         if (cfg->verbose_level > 3)
5053                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5054
5055         //Don't allow mixing reference types with value types
5056         if (param_klass->valuetype != return_klass->valuetype) {
5057                 if (cfg->verbose_level > 3)
5058                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5059                 return FALSE;
5060         }
5061
5062         if (!param_klass->valuetype) {
5063                 if (cfg->verbose_level > 3)
5064                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5065                 return TRUE;
5066         }
5067
5068         //That are blitable
5069         if (param_klass->has_references || return_klass->has_references)
5070                 return FALSE;
5071
5072         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5073         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5074                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5075                         if (cfg->verbose_level > 3)
5076                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5077                 return FALSE;
5078         }
5079
5080         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5081                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5082                 if (cfg->verbose_level > 3)
5083                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5084                 return FALSE;
5085         }
5086
5087         param_size = mono_class_value_size (param_klass, &align);
5088         return_size = mono_class_value_size (return_klass, &align);
5089
5090         //We can do it if sizes match
5091         if (param_size == return_size) {
5092                 if (cfg->verbose_level > 3)
5093                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5094                 return TRUE;
5095         }
5096
5097         //No simple way to handle struct if sizes don't match
5098         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5099                 if (cfg->verbose_level > 3)
5100                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5101                 return FALSE;
5102         }
5103
5104         /*
5105          * Same reg size category.
5106          * A quick note on why we don't require widening here.
5107          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5108          *
5109          * Since the source value comes from a function argument, the JIT will already have
5110          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5111          */
5112         if (param_size <= 4 && return_size <= 4) {
5113                 if (cfg->verbose_level > 3)
5114                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5115                 return TRUE;
5116         }
5117
5118         return FALSE;
5119 }
5120
5121 static MonoInst*
5122 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5123 {
5124         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5125         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5126
5127         if (mini_is_gsharedvt_variable_type (fsig->ret))
5128                 return NULL;
5129
5130         //Valuetypes that are semantically equivalent or numbers than can be widened to
5131         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5132                 return args [0];
5133
5134         //Arrays of valuetypes that are semantically equivalent
5135         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5136                 return args [0];
5137
5138         return NULL;
5139 }
5140
5141 static MonoInst*
5142 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5143 {
5144 #ifdef MONO_ARCH_SIMD_INTRINSICS
5145         MonoInst *ins = NULL;
5146
5147         if (cfg->opt & MONO_OPT_SIMD) {
5148                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5149                 if (ins)
5150                         return ins;
5151         }
5152 #endif
5153
5154         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5155 }
5156
5157 static MonoInst*
5158 emit_memory_barrier (MonoCompile *cfg, int kind)
5159 {
5160         MonoInst *ins = NULL;
5161         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5162         MONO_ADD_INS (cfg->cbb, ins);
5163         ins->backend.memory_barrier_kind = kind;
5164
5165         return ins;
5166 }
5167
5168 static MonoInst*
5169 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5170 {
5171         MonoInst *ins = NULL;
5172         int opcode = 0;
5173
5174         /* The LLVM backend supports these intrinsics */
5175         if (cmethod->klass == mono_defaults.math_class) {
5176                 if (strcmp (cmethod->name, "Sin") == 0) {
5177                         opcode = OP_SIN;
5178                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5179                         opcode = OP_COS;
5180                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5181                         opcode = OP_SQRT;
5182                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5183                         opcode = OP_ABS;
5184                 }
5185
5186                 if (opcode && fsig->param_count == 1) {
5187                         MONO_INST_NEW (cfg, ins, opcode);
5188                         ins->type = STACK_R8;
5189                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5190                         ins->sreg1 = args [0]->dreg;
5191                         MONO_ADD_INS (cfg->cbb, ins);
5192                 }
5193
5194                 opcode = 0;
5195                 if (cfg->opt & MONO_OPT_CMOV) {
5196                         if (strcmp (cmethod->name, "Min") == 0) {
5197                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5198                                         opcode = OP_IMIN;
5199                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5200                                         opcode = OP_IMIN_UN;
5201                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5202                                         opcode = OP_LMIN;
5203                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5204                                         opcode = OP_LMIN_UN;
5205                         } else if (strcmp (cmethod->name, "Max") == 0) {
5206                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5207                                         opcode = OP_IMAX;
5208                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5209                                         opcode = OP_IMAX_UN;
5210                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5211                                         opcode = OP_LMAX;
5212                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5213                                         opcode = OP_LMAX_UN;
5214                         }
5215                 }
5216
5217                 if (opcode && fsig->param_count == 2) {
5218                         MONO_INST_NEW (cfg, ins, opcode);
5219                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5220                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5221                         ins->sreg1 = args [0]->dreg;
5222                         ins->sreg2 = args [1]->dreg;
5223                         MONO_ADD_INS (cfg->cbb, ins);
5224                 }
5225         }
5226
5227         return ins;
5228 }
5229
5230 static MonoInst*
5231 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5232 {
5233         if (cmethod->klass == mono_defaults.array_class) {
5234                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5235                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5236                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5237                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5238                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5239                         return emit_array_unsafe_mov (cfg, fsig, args);
5240         }
5241
5242         return NULL;
5243 }
5244
5245 static MonoInst*
5246 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5247 {
5248         MonoInst *ins = NULL;
5249
5250          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5251
5252         if (cmethod->klass == mono_defaults.string_class) {
5253                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5254                         int dreg = alloc_ireg (cfg);
5255                         int index_reg = alloc_preg (cfg);
5256                         int add_reg = alloc_preg (cfg);
5257
5258 #if SIZEOF_REGISTER == 8
5259                         if (COMPILE_LLVM (cfg)) {
5260                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5261                         } else {
5262                                 /* The array reg is 64 bits but the index reg is only 32 */
5263                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5264                         }
5265 #else
5266                         index_reg = args [1]->dreg;
5267 #endif  
5268                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5269
5270 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5271                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5272                         add_reg = ins->dreg;
5273                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5274                                                                    add_reg, 0);
5275 #else
5276                         int mult_reg = alloc_preg (cfg);
5277                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5278                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5279                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5280                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5281 #endif
5282                         type_from_op (cfg, ins, NULL, NULL);
5283                         return ins;
5284                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5285                         int dreg = alloc_ireg (cfg);
5286                         /* Decompose later to allow more optimizations */
5287                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5288                         ins->type = STACK_I4;
5289                         ins->flags |= MONO_INST_FAULT;
5290                         cfg->cbb->has_array_access = TRUE;
5291                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5292
5293                         return ins;
5294                 } else 
5295                         return NULL;
5296         } else if (cmethod->klass == mono_defaults.object_class) {
5297                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5298                         int dreg = alloc_ireg_ref (cfg);
5299                         int vt_reg = alloc_preg (cfg);
5300                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5301                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5302                         type_from_op (cfg, ins, NULL, NULL);
5303
5304                         return ins;
5305                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5306                         int dreg = alloc_ireg (cfg);
5307                         int t1 = alloc_ireg (cfg);
5308         
5309                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5310                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5311                         ins->type = STACK_I4;
5312
5313                         return ins;
5314                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5315                         MONO_INST_NEW (cfg, ins, OP_NOP);
5316                         MONO_ADD_INS (cfg->cbb, ins);
5317                         return ins;
5318                 } else
5319                         return NULL;
5320         } else if (cmethod->klass == mono_defaults.array_class) {
5321                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5322                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5323                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5324                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5325
5326 #ifndef MONO_BIG_ARRAYS
5327                 /*
5328                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5329                  * Array methods.
5330                  */
5331                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5332                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5333                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5334                         int dreg = alloc_ireg (cfg);
5335                         int bounds_reg = alloc_ireg_mp (cfg);
5336                         MonoBasicBlock *end_bb, *szarray_bb;
5337                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5338
5339                         NEW_BBLOCK (cfg, end_bb);
5340                         NEW_BBLOCK (cfg, szarray_bb);
5341
5342                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5343                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5344                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5345                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5346                         /* Non-szarray case */
5347                         if (get_length)
5348                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5349                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5350                         else
5351                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5352                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5353                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5354                         MONO_START_BB (cfg, szarray_bb);
5355                         /* Szarray case */
5356                         if (get_length)
5357                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5358                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5359                         else
5360                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5361                         MONO_START_BB (cfg, end_bb);
5362
5363                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5364                         ins->type = STACK_I4;
5365                         
5366                         return ins;
5367                 }
5368 #endif
5369
5370                 if (cmethod->name [0] != 'g')
5371                         return NULL;
5372
5373                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5374                         int dreg = alloc_ireg (cfg);
5375                         int vtable_reg = alloc_preg (cfg);
5376                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5377                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5378                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5379                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5380                         type_from_op (cfg, ins, NULL, NULL);
5381
5382                         return ins;
5383                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5384                         int dreg = alloc_ireg (cfg);
5385
5386                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5387                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5388                         type_from_op (cfg, ins, NULL, NULL);
5389
5390                         return ins;
5391                 } else
5392                         return NULL;
5393         } else if (cmethod->klass == runtime_helpers_class) {
5394                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5395                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5396                         return ins;
5397                 } else
5398                         return NULL;
5399         } else if (cmethod->klass == mono_defaults.monitor_class) {
5400                 gboolean is_enter = FALSE;
5401                 gboolean is_v4 = FALSE;
5402
5403                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 2 && fsig->params [1]->byref) {
5404                         is_enter = TRUE;
5405                         is_v4 = TRUE;
5406                 }
5407                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 1)
5408                         is_enter = TRUE;
5409
5410                 if (is_enter) {
5411                         /*
5412                          * To make async stack traces work, icalls which can block should have a wrapper.
5413                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
5414                          */
5415                         MonoBasicBlock *end_bb;
5416
5417                         NEW_BBLOCK (cfg, end_bb);
5418
5419                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
5420                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
5421                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
5422                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_internal : (gpointer)mono_monitor_enter_internal, args);
5423                         MONO_START_BB (cfg, end_bb);
5424                         return ins;
5425                 }
5426         } else if (cmethod->klass == mono_defaults.thread_class) {
5427                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5428                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5429                         MONO_ADD_INS (cfg->cbb, ins);
5430                         return ins;
5431                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5432                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5433                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5434                         guint32 opcode = 0;
5435                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5436
5437                         if (fsig->params [0]->type == MONO_TYPE_I1)
5438                                 opcode = OP_LOADI1_MEMBASE;
5439                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5440                                 opcode = OP_LOADU1_MEMBASE;
5441                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5442                                 opcode = OP_LOADI2_MEMBASE;
5443                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5444                                 opcode = OP_LOADU2_MEMBASE;
5445                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5446                                 opcode = OP_LOADI4_MEMBASE;
5447                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5448                                 opcode = OP_LOADU4_MEMBASE;
5449                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5450                                 opcode = OP_LOADI8_MEMBASE;
5451                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5452                                 opcode = OP_LOADR4_MEMBASE;
5453                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5454                                 opcode = OP_LOADR8_MEMBASE;
5455                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5456                                 opcode = OP_LOAD_MEMBASE;
5457
5458                         if (opcode) {
5459                                 MONO_INST_NEW (cfg, ins, opcode);
5460                                 ins->inst_basereg = args [0]->dreg;
5461                                 ins->inst_offset = 0;
5462                                 MONO_ADD_INS (cfg->cbb, ins);
5463
5464                                 switch (fsig->params [0]->type) {
5465                                 case MONO_TYPE_I1:
5466                                 case MONO_TYPE_U1:
5467                                 case MONO_TYPE_I2:
5468                                 case MONO_TYPE_U2:
5469                                 case MONO_TYPE_I4:
5470                                 case MONO_TYPE_U4:
5471                                         ins->dreg = mono_alloc_ireg (cfg);
5472                                         ins->type = STACK_I4;
5473                                         break;
5474                                 case MONO_TYPE_I8:
5475                                 case MONO_TYPE_U8:
5476                                         ins->dreg = mono_alloc_lreg (cfg);
5477                                         ins->type = STACK_I8;
5478                                         break;
5479                                 case MONO_TYPE_I:
5480                                 case MONO_TYPE_U:
5481                                         ins->dreg = mono_alloc_ireg (cfg);
5482 #if SIZEOF_REGISTER == 8
5483                                         ins->type = STACK_I8;
5484 #else
5485                                         ins->type = STACK_I4;
5486 #endif
5487                                         break;
5488                                 case MONO_TYPE_R4:
5489                                 case MONO_TYPE_R8:
5490                                         ins->dreg = mono_alloc_freg (cfg);
5491                                         ins->type = STACK_R8;
5492                                         break;
5493                                 default:
5494                                         g_assert (mini_type_is_reference (fsig->params [0]));
5495                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5496                                         ins->type = STACK_OBJ;
5497                                         break;
5498                                 }
5499
5500                                 if (opcode == OP_LOADI8_MEMBASE)
5501                                         ins = mono_decompose_opcode (cfg, ins);
5502
5503                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5504
5505                                 return ins;
5506                         }
5507                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5508                         guint32 opcode = 0;
5509                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5510
5511                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5512                                 opcode = OP_STOREI1_MEMBASE_REG;
5513                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5514                                 opcode = OP_STOREI2_MEMBASE_REG;
5515                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5516                                 opcode = OP_STOREI4_MEMBASE_REG;
5517                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5518                                 opcode = OP_STOREI8_MEMBASE_REG;
5519                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5520                                 opcode = OP_STORER4_MEMBASE_REG;
5521                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5522                                 opcode = OP_STORER8_MEMBASE_REG;
5523                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5524                                 opcode = OP_STORE_MEMBASE_REG;
5525
5526                         if (opcode) {
5527                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5528
5529                                 MONO_INST_NEW (cfg, ins, opcode);
5530                                 ins->sreg1 = args [1]->dreg;
5531                                 ins->inst_destbasereg = args [0]->dreg;
5532                                 ins->inst_offset = 0;
5533                                 MONO_ADD_INS (cfg->cbb, ins);
5534
5535                                 if (opcode == OP_STOREI8_MEMBASE_REG)
5536                                         ins = mono_decompose_opcode (cfg, ins);
5537
5538                                 return ins;
5539                         }
5540                 }
5541         } else if (cmethod->klass->image == mono_defaults.corlib &&
5542                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5543                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5544                 ins = NULL;
5545
5546 #if SIZEOF_REGISTER == 8
5547                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5548                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
5549                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
5550                                 ins->dreg = mono_alloc_preg (cfg);
5551                                 ins->sreg1 = args [0]->dreg;
5552                                 ins->type = STACK_I8;
5553                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
5554                                 MONO_ADD_INS (cfg->cbb, ins);
5555                         } else {
5556                                 MonoInst *load_ins;
5557
5558                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5559
5560                                 /* 64 bit reads are already atomic */
5561                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
5562                                 load_ins->dreg = mono_alloc_preg (cfg);
5563                                 load_ins->inst_basereg = args [0]->dreg;
5564                                 load_ins->inst_offset = 0;
5565                                 load_ins->type = STACK_I8;
5566                                 MONO_ADD_INS (cfg->cbb, load_ins);
5567
5568                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5569
5570                                 ins = load_ins;
5571                         }
5572                 }
5573 #endif
5574
5575                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
5576                         MonoInst *ins_iconst;
5577                         guint32 opcode = 0;
5578
5579                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5580                                 opcode = OP_ATOMIC_ADD_I4;
5581                                 cfg->has_atomic_add_i4 = TRUE;
5582                         }
5583 #if SIZEOF_REGISTER == 8
5584                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5585                                 opcode = OP_ATOMIC_ADD_I8;
5586 #endif
5587                         if (opcode) {
5588                                 if (!mono_arch_opcode_supported (opcode))
5589                                         return NULL;
5590                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5591                                 ins_iconst->inst_c0 = 1;
5592                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5593                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5594
5595                                 MONO_INST_NEW (cfg, ins, opcode);
5596                                 ins->dreg = mono_alloc_ireg (cfg);
5597                                 ins->inst_basereg = args [0]->dreg;
5598                                 ins->inst_offset = 0;
5599                                 ins->sreg2 = ins_iconst->dreg;
5600                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5601                                 MONO_ADD_INS (cfg->cbb, ins);
5602                         }
5603                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
5604                         MonoInst *ins_iconst;
5605                         guint32 opcode = 0;
5606
5607                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5608                                 opcode = OP_ATOMIC_ADD_I4;
5609                                 cfg->has_atomic_add_i4 = TRUE;
5610                         }
5611 #if SIZEOF_REGISTER == 8
5612                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5613                                 opcode = OP_ATOMIC_ADD_I8;
5614 #endif
5615                         if (opcode) {
5616                                 if (!mono_arch_opcode_supported (opcode))
5617                                         return NULL;
5618                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5619                                 ins_iconst->inst_c0 = -1;
5620                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5621                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5622
5623                                 MONO_INST_NEW (cfg, ins, opcode);
5624                                 ins->dreg = mono_alloc_ireg (cfg);
5625                                 ins->inst_basereg = args [0]->dreg;
5626                                 ins->inst_offset = 0;
5627                                 ins->sreg2 = ins_iconst->dreg;
5628                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5629                                 MONO_ADD_INS (cfg->cbb, ins);
5630                         }
5631                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
5632                         guint32 opcode = 0;
5633
5634                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5635                                 opcode = OP_ATOMIC_ADD_I4;
5636                                 cfg->has_atomic_add_i4 = TRUE;
5637                         }
5638 #if SIZEOF_REGISTER == 8
5639                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5640                                 opcode = OP_ATOMIC_ADD_I8;
5641 #endif
5642                         if (opcode) {
5643                                 if (!mono_arch_opcode_supported (opcode))
5644                                         return NULL;
5645                                 MONO_INST_NEW (cfg, ins, opcode);
5646                                 ins->dreg = mono_alloc_ireg (cfg);
5647                                 ins->inst_basereg = args [0]->dreg;
5648                                 ins->inst_offset = 0;
5649                                 ins->sreg2 = args [1]->dreg;
5650                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5651                                 MONO_ADD_INS (cfg->cbb, ins);
5652                         }
5653                 }
5654                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
5655                         MonoInst *f2i = NULL, *i2f;
5656                         guint32 opcode, f2i_opcode, i2f_opcode;
5657                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5658                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
5659
5660                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
5661                             fsig->params [0]->type == MONO_TYPE_R4) {
5662                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5663                                 f2i_opcode = OP_MOVE_F_TO_I4;
5664                                 i2f_opcode = OP_MOVE_I4_TO_F;
5665                                 cfg->has_atomic_exchange_i4 = TRUE;
5666                         }
5667 #if SIZEOF_REGISTER == 8
5668                         else if (is_ref ||
5669                                  fsig->params [0]->type == MONO_TYPE_I8 ||
5670                                  fsig->params [0]->type == MONO_TYPE_R8 ||
5671                                  fsig->params [0]->type == MONO_TYPE_I) {
5672                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5673                                 f2i_opcode = OP_MOVE_F_TO_I8;
5674                                 i2f_opcode = OP_MOVE_I8_TO_F;
5675                         }
5676 #else
5677                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
5678                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5679                                 cfg->has_atomic_exchange_i4 = TRUE;
5680                         }
5681 #endif
5682                         else
5683                                 return NULL;
5684
5685                         if (!mono_arch_opcode_supported (opcode))
5686                                 return NULL;
5687
5688                         if (is_float) {
5689                                 /* TODO: Decompose these opcodes instead of bailing here. */
5690                                 if (COMPILE_SOFT_FLOAT (cfg))
5691                                         return NULL;
5692
5693                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
5694                                 f2i->dreg = mono_alloc_ireg (cfg);
5695                                 f2i->sreg1 = args [1]->dreg;
5696                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5697                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5698                                 MONO_ADD_INS (cfg->cbb, f2i);
5699                         }
5700
5701                         MONO_INST_NEW (cfg, ins, opcode);
5702                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5703                         ins->inst_basereg = args [0]->dreg;
5704                         ins->inst_offset = 0;
5705                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
5706                         MONO_ADD_INS (cfg->cbb, ins);
5707
5708                         switch (fsig->params [0]->type) {
5709                         case MONO_TYPE_I4:
5710                                 ins->type = STACK_I4;
5711                                 break;
5712                         case MONO_TYPE_I8:
5713                                 ins->type = STACK_I8;
5714                                 break;
5715                         case MONO_TYPE_I:
5716 #if SIZEOF_REGISTER == 8
5717                                 ins->type = STACK_I8;
5718 #else
5719                                 ins->type = STACK_I4;
5720 #endif
5721                                 break;
5722                         case MONO_TYPE_R4:
5723                         case MONO_TYPE_R8:
5724                                 ins->type = STACK_R8;
5725                                 break;
5726                         default:
5727                                 g_assert (mini_type_is_reference (fsig->params [0]));
5728                                 ins->type = STACK_OBJ;
5729                                 break;
5730                         }
5731
5732                         if (is_float) {
5733                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5734                                 i2f->dreg = mono_alloc_freg (cfg);
5735                                 i2f->sreg1 = ins->dreg;
5736                                 i2f->type = STACK_R8;
5737                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5738                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5739                                 MONO_ADD_INS (cfg->cbb, i2f);
5740
5741                                 ins = i2f;
5742                         }
5743
5744                         if (cfg->gen_write_barriers && is_ref)
5745                                 emit_write_barrier (cfg, args [0], args [1]);
5746                 }
5747                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
5748                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
5749                         guint32 opcode, f2i_opcode, i2f_opcode;
5750                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
5751                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
5752
5753                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
5754                             fsig->params [1]->type == MONO_TYPE_R4) {
5755                                 opcode = OP_ATOMIC_CAS_I4;
5756                                 f2i_opcode = OP_MOVE_F_TO_I4;
5757                                 i2f_opcode = OP_MOVE_I4_TO_F;
5758                                 cfg->has_atomic_cas_i4 = TRUE;
5759                         }
5760 #if SIZEOF_REGISTER == 8
5761                         else if (is_ref ||
5762                                  fsig->params [1]->type == MONO_TYPE_I8 ||
5763                                  fsig->params [1]->type == MONO_TYPE_R8 ||
5764                                  fsig->params [1]->type == MONO_TYPE_I) {
5765                                 opcode = OP_ATOMIC_CAS_I8;
5766                                 f2i_opcode = OP_MOVE_F_TO_I8;
5767                                 i2f_opcode = OP_MOVE_I8_TO_F;
5768                         }
5769 #else
5770                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
5771                                 opcode = OP_ATOMIC_CAS_I4;
5772                                 cfg->has_atomic_cas_i4 = TRUE;
5773                         }
5774 #endif
5775                         else
5776                                 return NULL;
5777
5778                         if (!mono_arch_opcode_supported (opcode))
5779                                 return NULL;
5780
5781                         if (is_float) {
5782                                 /* TODO: Decompose these opcodes instead of bailing here. */
5783                                 if (COMPILE_SOFT_FLOAT (cfg))
5784                                         return NULL;
5785
5786                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
5787                                 f2i_new->dreg = mono_alloc_ireg (cfg);
5788                                 f2i_new->sreg1 = args [1]->dreg;
5789                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5790                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5791                                 MONO_ADD_INS (cfg->cbb, f2i_new);
5792
5793                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
5794                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
5795                                 f2i_cmp->sreg1 = args [2]->dreg;
5796                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5797                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5798                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
5799                         }
5800
5801                         MONO_INST_NEW (cfg, ins, opcode);
5802                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5803                         ins->sreg1 = args [0]->dreg;
5804                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
5805                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
5806                         MONO_ADD_INS (cfg->cbb, ins);
5807
5808                         switch (fsig->params [1]->type) {
5809                         case MONO_TYPE_I4:
5810                                 ins->type = STACK_I4;
5811                                 break;
5812                         case MONO_TYPE_I8:
5813                                 ins->type = STACK_I8;
5814                                 break;
5815                         case MONO_TYPE_I:
5816 #if SIZEOF_REGISTER == 8
5817                                 ins->type = STACK_I8;
5818 #else
5819                                 ins->type = STACK_I4;
5820 #endif
5821                                 break;
5822                         case MONO_TYPE_R4:
5823                                 ins->type = cfg->r4_stack_type;
5824                                 break;
5825                         case MONO_TYPE_R8:
5826                                 ins->type = STACK_R8;
5827                                 break;
5828                         default:
5829                                 g_assert (mini_type_is_reference (fsig->params [1]));
5830                                 ins->type = STACK_OBJ;
5831                                 break;
5832                         }
5833
5834                         if (is_float) {
5835                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5836                                 i2f->dreg = mono_alloc_freg (cfg);
5837                                 i2f->sreg1 = ins->dreg;
5838                                 i2f->type = STACK_R8;
5839                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5840                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5841                                 MONO_ADD_INS (cfg->cbb, i2f);
5842
5843                                 ins = i2f;
5844                         }
5845
5846                         if (cfg->gen_write_barriers && is_ref)
5847                                 emit_write_barrier (cfg, args [0], args [1]);
5848                 }
5849                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
5850                          fsig->params [1]->type == MONO_TYPE_I4) {
5851                         MonoInst *cmp, *ceq;
5852
5853                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5854                                 return NULL;
5855
5856                         /* int32 r = CAS (location, value, comparand); */
5857                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5858                         ins->dreg = alloc_ireg (cfg);
5859                         ins->sreg1 = args [0]->dreg;
5860                         ins->sreg2 = args [1]->dreg;
5861                         ins->sreg3 = args [2]->dreg;
5862                         ins->type = STACK_I4;
5863                         MONO_ADD_INS (cfg->cbb, ins);
5864
5865                         /* bool result = r == comparand; */
5866                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
5867                         cmp->sreg1 = ins->dreg;
5868                         cmp->sreg2 = args [2]->dreg;
5869                         cmp->type = STACK_I4;
5870                         MONO_ADD_INS (cfg->cbb, cmp);
5871
5872                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
5873                         ceq->dreg = alloc_ireg (cfg);
5874                         ceq->type = STACK_I4;
5875                         MONO_ADD_INS (cfg->cbb, ceq);
5876
5877                         /* *success = result; */
5878                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
5879
5880                         cfg->has_atomic_cas_i4 = TRUE;
5881                 }
5882                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
5883                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5884
5885                 if (ins)
5886                         return ins;
5887         } else if (cmethod->klass->image == mono_defaults.corlib &&
5888                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5889                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
5890                 ins = NULL;
5891
5892                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
5893                         guint32 opcode = 0;
5894                         MonoType *t = fsig->params [0];
5895                         gboolean is_ref;
5896                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
5897
5898                         g_assert (t->byref);
5899                         /* t is a byref type, so the reference check is more complicated */
5900                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5901                         if (t->type == MONO_TYPE_I1)
5902                                 opcode = OP_ATOMIC_LOAD_I1;
5903                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5904                                 opcode = OP_ATOMIC_LOAD_U1;
5905                         else if (t->type == MONO_TYPE_I2)
5906                                 opcode = OP_ATOMIC_LOAD_I2;
5907                         else if (t->type == MONO_TYPE_U2)
5908                                 opcode = OP_ATOMIC_LOAD_U2;
5909                         else if (t->type == MONO_TYPE_I4)
5910                                 opcode = OP_ATOMIC_LOAD_I4;
5911                         else if (t->type == MONO_TYPE_U4)
5912                                 opcode = OP_ATOMIC_LOAD_U4;
5913                         else if (t->type == MONO_TYPE_R4)
5914                                 opcode = OP_ATOMIC_LOAD_R4;
5915                         else if (t->type == MONO_TYPE_R8)
5916                                 opcode = OP_ATOMIC_LOAD_R8;
5917 #if SIZEOF_REGISTER == 8
5918                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
5919                                 opcode = OP_ATOMIC_LOAD_I8;
5920                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
5921                                 opcode = OP_ATOMIC_LOAD_U8;
5922 #else
5923                         else if (t->type == MONO_TYPE_I)
5924                                 opcode = OP_ATOMIC_LOAD_I4;
5925                         else if (is_ref || t->type == MONO_TYPE_U)
5926                                 opcode = OP_ATOMIC_LOAD_U4;
5927 #endif
5928
5929                         if (opcode) {
5930                                 if (!mono_arch_opcode_supported (opcode))
5931                                         return NULL;
5932
5933                                 MONO_INST_NEW (cfg, ins, opcode);
5934                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
5935                                 ins->sreg1 = args [0]->dreg;
5936                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
5937                                 MONO_ADD_INS (cfg->cbb, ins);
5938
5939                                 switch (t->type) {
5940                                 case MONO_TYPE_BOOLEAN:
5941                                 case MONO_TYPE_I1:
5942                                 case MONO_TYPE_U1:
5943                                 case MONO_TYPE_I2:
5944                                 case MONO_TYPE_U2:
5945                                 case MONO_TYPE_I4:
5946                                 case MONO_TYPE_U4:
5947                                         ins->type = STACK_I4;
5948                                         break;
5949                                 case MONO_TYPE_I8:
5950                                 case MONO_TYPE_U8:
5951                                         ins->type = STACK_I8;
5952                                         break;
5953                                 case MONO_TYPE_I:
5954                                 case MONO_TYPE_U:
5955 #if SIZEOF_REGISTER == 8
5956                                         ins->type = STACK_I8;
5957 #else
5958                                         ins->type = STACK_I4;
5959 #endif
5960                                         break;
5961                                 case MONO_TYPE_R4:
5962                                         ins->type = cfg->r4_stack_type;
5963                                         break;
5964                                 case MONO_TYPE_R8:
5965                                         ins->type = STACK_R8;
5966                                         break;
5967                                 default:
5968                                         g_assert (is_ref);
5969                                         ins->type = STACK_OBJ;
5970                                         break;
5971                                 }
5972                         }
5973                 }
5974
5975                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
5976                         guint32 opcode = 0;
5977                         MonoType *t = fsig->params [0];
5978                         gboolean is_ref;
5979
5980                         g_assert (t->byref);
5981                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5982                         if (t->type == MONO_TYPE_I1)
5983                                 opcode = OP_ATOMIC_STORE_I1;
5984                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5985                                 opcode = OP_ATOMIC_STORE_U1;
5986                         else if (t->type == MONO_TYPE_I2)
5987                                 opcode = OP_ATOMIC_STORE_I2;
5988                         else if (t->type == MONO_TYPE_U2)
5989                                 opcode = OP_ATOMIC_STORE_U2;
5990                         else if (t->type == MONO_TYPE_I4)
5991                                 opcode = OP_ATOMIC_STORE_I4;
5992                         else if (t->type == MONO_TYPE_U4)
5993                                 opcode = OP_ATOMIC_STORE_U4;
5994                         else if (t->type == MONO_TYPE_R4)
5995                                 opcode = OP_ATOMIC_STORE_R4;
5996                         else if (t->type == MONO_TYPE_R8)
5997                                 opcode = OP_ATOMIC_STORE_R8;
5998 #if SIZEOF_REGISTER == 8
5999                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6000                                 opcode = OP_ATOMIC_STORE_I8;
6001                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6002                                 opcode = OP_ATOMIC_STORE_U8;
6003 #else
6004                         else if (t->type == MONO_TYPE_I)
6005                                 opcode = OP_ATOMIC_STORE_I4;
6006                         else if (is_ref || t->type == MONO_TYPE_U)
6007                                 opcode = OP_ATOMIC_STORE_U4;
6008 #endif
6009
6010                         if (opcode) {
6011                                 if (!mono_arch_opcode_supported (opcode))
6012                                         return NULL;
6013
6014                                 MONO_INST_NEW (cfg, ins, opcode);
6015                                 ins->dreg = args [0]->dreg;
6016                                 ins->sreg1 = args [1]->dreg;
6017                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6018                                 MONO_ADD_INS (cfg->cbb, ins);
6019
6020                                 if (cfg->gen_write_barriers && is_ref)
6021                                         emit_write_barrier (cfg, args [0], args [1]);
6022                         }
6023                 }
6024
6025                 if (ins)
6026                         return ins;
6027         } else if (cmethod->klass->image == mono_defaults.corlib &&
6028                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6029                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6030                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6031                         if (should_insert_brekpoint (cfg->method)) {
6032                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6033                         } else {
6034                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6035                                 MONO_ADD_INS (cfg->cbb, ins);
6036                         }
6037                         return ins;
6038                 }
6039         } else if (cmethod->klass->image == mono_defaults.corlib &&
6040                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6041                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6042                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6043 #ifdef TARGET_WIN32
6044                         EMIT_NEW_ICONST (cfg, ins, 1);
6045 #else
6046                         EMIT_NEW_ICONST (cfg, ins, 0);
6047 #endif
6048                 }
6049         } else if (cmethod->klass->image == mono_defaults.corlib &&
6050                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6051                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6052                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6053                         /* No stack walks are currently available, so implement this as an intrinsic */
6054                         MonoInst *assembly_ins;
6055
6056                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6057                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6058                         return ins;
6059                 }
6060         } else if (cmethod->klass->image == mono_defaults.corlib &&
6061                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6062                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6063                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6064                         /* No stack walks are currently available, so implement this as an intrinsic */
6065                         MonoInst *method_ins;
6066                         MonoMethod *declaring = cfg->method;
6067
6068                         /* This returns the declaring generic method */
6069                         if (declaring->is_inflated)
6070                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6071                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6072                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6073                         cfg->no_inline = TRUE;
6074                         if (cfg->method != cfg->current_method)
6075                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6076                         return ins;
6077                 }
6078         } else if (cmethod->klass == mono_defaults.math_class) {
6079                 /* 
6080                  * There is general branchless code for Min/Max, but it does not work for 
6081                  * all inputs:
6082                  * http://everything2.com/?node_id=1051618
6083                  */
6084         } else if (cmethod->klass == mono_defaults.systemtype_class && !strcmp (cmethod->name, "op_Equality")) {
6085                 EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg);
6086                 MONO_INST_NEW (cfg, ins, OP_PCEQ);
6087                 ins->dreg = alloc_preg (cfg);
6088                 ins->type = STACK_I4;
6089                 MONO_ADD_INS (cfg->cbb, ins);
6090                 return ins;
6091         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6092                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6093                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6094                                 !strcmp (cmethod->klass->name, "Selector")) ||
6095                            ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
6096                                  !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
6097                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6098                                 !strcmp (cmethod->klass->name, "Selector"))
6099                            ) {
6100                 if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
6101                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6102                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6103                     cfg->compile_aot) {
6104                         MonoInst *pi;
6105                         MonoJumpInfoToken *ji;
6106                         char *s;
6107
6108                         if (args [0]->opcode == OP_GOT_ENTRY) {
6109                                 pi = (MonoInst *)args [0]->inst_p1;
6110                                 g_assert (pi->opcode == OP_PATCH_INFO);
6111                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6112                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6113                         } else {
6114                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6115                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6116                         }
6117
6118                         NULLIFY_INS (args [0]);
6119
6120                         s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
6121                         return_val_if_nok (&cfg->error, NULL);
6122
6123                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6124                         ins->dreg = mono_alloc_ireg (cfg);
6125                         // FIXME: Leaks
6126                         ins->inst_p0 = s;
6127                         MONO_ADD_INS (cfg->cbb, ins);
6128                         return ins;
6129                 }
6130         }
6131
6132 #ifdef MONO_ARCH_SIMD_INTRINSICS
6133         if (cfg->opt & MONO_OPT_SIMD) {
6134                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6135                 if (ins)
6136                         return ins;
6137         }
6138 #endif
6139
6140         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6141         if (ins)
6142                 return ins;
6143
6144         if (COMPILE_LLVM (cfg)) {
6145                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6146                 if (ins)
6147                         return ins;
6148         }
6149
6150         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6151 }
6152
6153 /*
6154  * This entry point could be used later for arbitrary method
6155  * redirection.
6156  */
6157 inline static MonoInst*
6158 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6159                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6160 {
6161         if (method->klass == mono_defaults.string_class) {
6162                 /* managed string allocation support */
6163                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6164                         MonoInst *iargs [2];
6165                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6166                         MonoMethod *managed_alloc = NULL;
6167
6168                         g_assert (vtable); /*Should not fail since it System.String*/
6169 #ifndef MONO_CROSS_COMPILE
6170                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6171 #endif
6172                         if (!managed_alloc)
6173                                 return NULL;
6174                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6175                         iargs [1] = args [0];
6176                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6177                 }
6178         }
6179         return NULL;
6180 }
6181
6182 static void
6183 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6184 {
6185         MonoInst *store, *temp;
6186         int i;
6187
6188         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6189                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6190
6191                 /*
6192                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6193                  * would be different than the MonoInst's used to represent arguments, and
6194                  * the ldelema implementation can't deal with that.
6195                  * Solution: When ldelema is used on an inline argument, create a var for 
6196                  * it, emit ldelema on that var, and emit the saving code below in
6197                  * inline_method () if needed.
6198                  */
6199                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6200                 cfg->args [i] = temp;
6201                 /* This uses cfg->args [i] which is set by the preceeding line */
6202                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6203                 store->cil_code = sp [0]->cil_code;
6204                 sp++;
6205         }
6206 }
6207
6208 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6209 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6210
6211 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6212 static gboolean
6213 check_inline_called_method_name_limit (MonoMethod *called_method)
6214 {
6215         int strncmp_result;
6216         static const char *limit = NULL;
6217         
6218         if (limit == NULL) {
6219                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6220
6221                 if (limit_string != NULL)
6222                         limit = limit_string;
6223                 else
6224                         limit = "";
6225         }
6226
6227         if (limit [0] != '\0') {
6228                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6229
6230                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6231                 g_free (called_method_name);
6232         
6233                 //return (strncmp_result <= 0);
6234                 return (strncmp_result == 0);
6235         } else {
6236                 return TRUE;
6237         }
6238 }
6239 #endif
6240
6241 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6242 static gboolean
6243 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6244 {
6245         int strncmp_result;
6246         static const char *limit = NULL;
6247         
6248         if (limit == NULL) {
6249                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6250                 if (limit_string != NULL) {
6251                         limit = limit_string;
6252                 } else {
6253                         limit = "";
6254                 }
6255         }
6256
6257         if (limit [0] != '\0') {
6258                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6259
6260                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6261                 g_free (caller_method_name);
6262         
6263                 //return (strncmp_result <= 0);
6264                 return (strncmp_result == 0);
6265         } else {
6266                 return TRUE;
6267         }
6268 }
6269 #endif
6270
6271 static void
6272 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6273 {
6274         static double r8_0 = 0.0;
6275         static float r4_0 = 0.0;
6276         MonoInst *ins;
6277         int t;
6278
6279         rtype = mini_get_underlying_type (rtype);
6280         t = rtype->type;
6281
6282         if (rtype->byref) {
6283                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6284         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6285                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6286         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6287                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6288         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6289                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6290                 ins->type = STACK_R4;
6291                 ins->inst_p0 = (void*)&r4_0;
6292                 ins->dreg = dreg;
6293                 MONO_ADD_INS (cfg->cbb, ins);
6294         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6295                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6296                 ins->type = STACK_R8;
6297                 ins->inst_p0 = (void*)&r8_0;
6298                 ins->dreg = dreg;
6299                 MONO_ADD_INS (cfg->cbb, ins);
6300         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6301                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6302                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6303         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6304                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6305         } else {
6306                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6307         }
6308 }
6309
6310 static void
6311 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6312 {
6313         int t;
6314
6315         rtype = mini_get_underlying_type (rtype);
6316         t = rtype->type;
6317
6318         if (rtype->byref) {
6319                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6320         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6321                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6322         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6323                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6324         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6325                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6326         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6327                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6328         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6329                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6330                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6331         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6332                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6333         } else {
6334                 emit_init_rvar (cfg, dreg, rtype);
6335         }
6336 }
6337
6338 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6339 static void
6340 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6341 {
6342         MonoInst *var = cfg->locals [local];
6343         if (COMPILE_SOFT_FLOAT (cfg)) {
6344                 MonoInst *store;
6345                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
6346                 emit_init_rvar (cfg, reg, type);
6347                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6348         } else {
6349                 if (init)
6350                         emit_init_rvar (cfg, var->dreg, type);
6351                 else
6352                         emit_dummy_init_rvar (cfg, var->dreg, type);
6353         }
6354 }
6355
6356 int
6357 mini_inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, guchar *ip, guint real_offset, gboolean inline_always)
6358 {
6359         return inline_method (cfg, cmethod, fsig, sp, ip, real_offset, inline_always);
6360 }
6361
6362 /*
6363  * inline_method:
6364  *
6365  * Return the cost of inlining CMETHOD, or zero if it should not be inlined.
6366  */
6367 static int
6368 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6369                guchar *ip, guint real_offset, gboolean inline_always)
6370 {
6371         MonoError error;
6372         MonoInst *ins, *rvar = NULL;
6373         MonoMethodHeader *cheader;
6374         MonoBasicBlock *ebblock, *sbblock;
6375         int i, costs;
6376         MonoMethod *prev_inlined_method;
6377         MonoInst **prev_locals, **prev_args;
6378         MonoType **prev_arg_types;
6379         guint prev_real_offset;
6380         GHashTable *prev_cbb_hash;
6381         MonoBasicBlock **prev_cil_offset_to_bb;
6382         MonoBasicBlock *prev_cbb;
6383         const unsigned char *prev_ip;
6384         unsigned char *prev_cil_start;
6385         guint32 prev_cil_offset_to_bb_len;
6386         MonoMethod *prev_current_method;
6387         MonoGenericContext *prev_generic_context;
6388         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
6389
6390         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6391
6392 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6393         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6394                 return 0;
6395 #endif
6396 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6397         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6398                 return 0;
6399 #endif
6400
6401         if (!fsig)
6402                 fsig = mono_method_signature (cmethod);
6403
6404         if (cfg->verbose_level > 2)
6405                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6406
6407         if (!cmethod->inline_info) {
6408                 cfg->stat_inlineable_methods++;
6409                 cmethod->inline_info = 1;
6410         }
6411
6412         /* allocate local variables */
6413         cheader = mono_method_get_header_checked (cmethod, &error);
6414         if (!cheader) {
6415                 if (inline_always) {
6416                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
6417                         mono_error_move (&cfg->error, &error);
6418                 } else {
6419                         mono_error_cleanup (&error);
6420                 }
6421                 return 0;
6422         }
6423
6424         /*Must verify before creating locals as it can cause the JIT to assert.*/
6425         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6426                 mono_metadata_free_mh (cheader);
6427                 return 0;
6428         }
6429
6430         /* allocate space to store the return value */
6431         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6432                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6433         }
6434
6435         prev_locals = cfg->locals;
6436         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
6437         for (i = 0; i < cheader->num_locals; ++i)
6438                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6439
6440         /* allocate start and end blocks */
6441         /* This is needed so if the inline is aborted, we can clean up */
6442         NEW_BBLOCK (cfg, sbblock);
6443         sbblock->real_offset = real_offset;
6444
6445         NEW_BBLOCK (cfg, ebblock);
6446         ebblock->block_num = cfg->num_bblocks++;
6447         ebblock->real_offset = real_offset;
6448
6449         prev_args = cfg->args;
6450         prev_arg_types = cfg->arg_types;
6451         prev_inlined_method = cfg->inlined_method;
6452         cfg->inlined_method = cmethod;
6453         cfg->ret_var_set = FALSE;
6454         cfg->inline_depth ++;
6455         prev_real_offset = cfg->real_offset;
6456         prev_cbb_hash = cfg->cbb_hash;
6457         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6458         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6459         prev_cil_start = cfg->cil_start;
6460         prev_ip = cfg->ip;
6461         prev_cbb = cfg->cbb;
6462         prev_current_method = cfg->current_method;
6463         prev_generic_context = cfg->generic_context;
6464         prev_ret_var_set = cfg->ret_var_set;
6465         prev_disable_inline = cfg->disable_inline;
6466
6467         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6468                 virtual_ = TRUE;
6469
6470         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
6471
6472         ret_var_set = cfg->ret_var_set;
6473
6474         cfg->inlined_method = prev_inlined_method;
6475         cfg->real_offset = prev_real_offset;
6476         cfg->cbb_hash = prev_cbb_hash;
6477         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6478         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6479         cfg->cil_start = prev_cil_start;
6480         cfg->ip = prev_ip;
6481         cfg->locals = prev_locals;
6482         cfg->args = prev_args;
6483         cfg->arg_types = prev_arg_types;
6484         cfg->current_method = prev_current_method;
6485         cfg->generic_context = prev_generic_context;
6486         cfg->ret_var_set = prev_ret_var_set;
6487         cfg->disable_inline = prev_disable_inline;
6488         cfg->inline_depth --;
6489
6490         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
6491                 if (cfg->verbose_level > 2)
6492                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6493
6494                 cfg->stat_inlined_methods++;
6495
6496                 /* always add some code to avoid block split failures */
6497                 MONO_INST_NEW (cfg, ins, OP_NOP);
6498                 MONO_ADD_INS (prev_cbb, ins);
6499
6500                 prev_cbb->next_bb = sbblock;
6501                 link_bblock (cfg, prev_cbb, sbblock);
6502
6503                 /* 
6504                  * Get rid of the begin and end bblocks if possible to aid local
6505                  * optimizations.
6506                  */
6507                 if (prev_cbb->out_count == 1)
6508                         mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6509
6510                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6511                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6512
6513                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6514                         MonoBasicBlock *prev = ebblock->in_bb [0];
6515
6516                         if (prev->next_bb == ebblock) {
6517                                 mono_merge_basic_blocks (cfg, prev, ebblock);
6518                                 cfg->cbb = prev;
6519                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6520                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
6521                                         cfg->cbb = prev_cbb;
6522                                 }
6523                         } else {
6524                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
6525                                 cfg->cbb = ebblock;
6526                         }
6527                 } else {
6528                         /* 
6529                          * Its possible that the rvar is set in some prev bblock, but not in others.
6530                          * (#1835).
6531                          */
6532                         if (rvar) {
6533                                 MonoBasicBlock *bb;
6534
6535                                 for (i = 0; i < ebblock->in_count; ++i) {
6536                                         bb = ebblock->in_bb [i];
6537
6538                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6539                                                 cfg->cbb = bb;
6540
6541                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6542                                         }
6543                                 }
6544                         }
6545
6546                         cfg->cbb = ebblock;
6547                 }
6548
6549                 if (rvar) {
6550                         /*
6551                          * If the inlined method contains only a throw, then the ret var is not 
6552                          * set, so set it to a dummy value.
6553                          */
6554                         if (!ret_var_set)
6555                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6556
6557                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6558                         *sp++ = ins;
6559                 }
6560                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6561                 return costs + 1;
6562         } else {
6563                 if (cfg->verbose_level > 2)
6564                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6565                 cfg->exception_type = MONO_EXCEPTION_NONE;
6566
6567                 /* This gets rid of the newly added bblocks */
6568                 cfg->cbb = prev_cbb;
6569         }
6570         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6571         return 0;
6572 }
6573
6574 /*
6575  * Some of these comments may well be out-of-date.
6576  * Design decisions: we do a single pass over the IL code (and we do bblock 
6577  * splitting/merging in the few cases when it's required: a back jump to an IL
6578  * address that was not already seen as bblock starting point).
6579  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6580  * Complex operations are decomposed in simpler ones right away. We need to let the 
6581  * arch-specific code peek and poke inside this process somehow (except when the 
6582  * optimizations can take advantage of the full semantic info of coarse opcodes).
6583  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6584  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6585  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6586  * opcode with value bigger than OP_LAST.
6587  * At this point the IR can be handed over to an interpreter, a dumb code generator
6588  * or to the optimizing code generator that will translate it to SSA form.
6589  *
6590  * Profiling directed optimizations.
6591  * We may compile by default with few or no optimizations and instrument the code
6592  * or the user may indicate what methods to optimize the most either in a config file
6593  * or through repeated runs where the compiler applies offline the optimizations to 
6594  * each method and then decides if it was worth it.
6595  */
6596
6597 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6598 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6599 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6600 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6601 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6602 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6603 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6604 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
6605
6606 /* offset from br.s -> br like opcodes */
6607 #define BIG_BRANCH_OFFSET 13
6608
6609 static gboolean
6610 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6611 {
6612         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6613
6614         return b == NULL || b == bb;
6615 }
6616
6617 static int
6618 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6619 {
6620         unsigned char *ip = start;
6621         unsigned char *target;
6622         int i;
6623         guint cli_addr;
6624         MonoBasicBlock *bblock;
6625         const MonoOpcode *opcode;
6626
6627         while (ip < end) {
6628                 cli_addr = ip - start;
6629                 i = mono_opcode_value ((const guint8 **)&ip, end);
6630                 if (i < 0)
6631                         UNVERIFIED;
6632                 opcode = &mono_opcodes [i];
6633                 switch (opcode->argument) {
6634                 case MonoInlineNone:
6635                         ip++; 
6636                         break;
6637                 case MonoInlineString:
6638                 case MonoInlineType:
6639                 case MonoInlineField:
6640                 case MonoInlineMethod:
6641                 case MonoInlineTok:
6642                 case MonoInlineSig:
6643                 case MonoShortInlineR:
6644                 case MonoInlineI:
6645                         ip += 5;
6646                         break;
6647                 case MonoInlineVar:
6648                         ip += 3;
6649                         break;
6650                 case MonoShortInlineVar:
6651                 case MonoShortInlineI:
6652                         ip += 2;
6653                         break;
6654                 case MonoShortInlineBrTarget:
6655                         target = start + cli_addr + 2 + (signed char)ip [1];
6656                         GET_BBLOCK (cfg, bblock, target);
6657                         ip += 2;
6658                         if (ip < end)
6659                                 GET_BBLOCK (cfg, bblock, ip);
6660                         break;
6661                 case MonoInlineBrTarget:
6662                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6663                         GET_BBLOCK (cfg, bblock, target);
6664                         ip += 5;
6665                         if (ip < end)
6666                                 GET_BBLOCK (cfg, bblock, ip);
6667                         break;
6668                 case MonoInlineSwitch: {
6669                         guint32 n = read32 (ip + 1);
6670                         guint32 j;
6671                         ip += 5;
6672                         cli_addr += 5 + 4 * n;
6673                         target = start + cli_addr;
6674                         GET_BBLOCK (cfg, bblock, target);
6675                         
6676                         for (j = 0; j < n; ++j) {
6677                                 target = start + cli_addr + (gint32)read32 (ip);
6678                                 GET_BBLOCK (cfg, bblock, target);
6679                                 ip += 4;
6680                         }
6681                         break;
6682                 }
6683                 case MonoInlineR:
6684                 case MonoInlineI8:
6685                         ip += 9;
6686                         break;
6687                 default:
6688                         g_assert_not_reached ();
6689                 }
6690
6691                 if (i == CEE_THROW) {
6692                         unsigned char *bb_start = ip - 1;
6693                         
6694                         /* Find the start of the bblock containing the throw */
6695                         bblock = NULL;
6696                         while ((bb_start >= start) && !bblock) {
6697                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6698                                 bb_start --;
6699                         }
6700                         if (bblock)
6701                                 bblock->out_of_line = 1;
6702                 }
6703         }
6704         return 0;
6705 unverified:
6706 exception_exit:
6707         *pos = ip;
6708         return 1;
6709 }
6710
6711 static inline MonoMethod *
6712 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
6713 {
6714         MonoMethod *method;
6715
6716         error_init (error);
6717
6718         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6719                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
6720                 if (context) {
6721                         method = mono_class_inflate_generic_method_checked (method, context, error);
6722                 }
6723         } else {
6724                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
6725         }
6726
6727         return method;
6728 }
6729
6730 static inline MonoMethod *
6731 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6732 {
6733         MonoError error;
6734         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
6735
6736         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
6737                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
6738                 method = NULL;
6739         }
6740
6741         if (!method && !cfg)
6742                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6743
6744         return method;
6745 }
6746
6747 static inline MonoClass*
6748 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6749 {
6750         MonoError error;
6751         MonoClass *klass;
6752
6753         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6754                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
6755                 if (context) {
6756                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
6757                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6758                 }
6759         } else {
6760                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
6761                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6762         }
6763         if (klass)
6764                 mono_class_init (klass);
6765         return klass;
6766 }
6767
6768 static inline MonoMethodSignature*
6769 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
6770 {
6771         MonoMethodSignature *fsig;
6772
6773         error_init (error);
6774         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6775                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6776         } else {
6777                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
6778                 return_val_if_nok (error, NULL);
6779         }
6780         if (context) {
6781                 fsig = mono_inflate_generic_signature(fsig, context, error);
6782         }
6783         return fsig;
6784 }
6785
6786 static MonoMethod*
6787 throw_exception (void)
6788 {
6789         static MonoMethod *method = NULL;
6790
6791         if (!method) {
6792                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6793                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6794         }
6795         g_assert (method);
6796         return method;
6797 }
6798
6799 static void
6800 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6801 {
6802         MonoMethod *thrower = throw_exception ();
6803         MonoInst *args [1];
6804
6805         EMIT_NEW_PCONST (cfg, args [0], ex);
6806         mono_emit_method_call (cfg, thrower, args, NULL);
6807 }
6808
6809 /*
6810  * Return the original method is a wrapper is specified. We can only access 
6811  * the custom attributes from the original method.
6812  */
6813 static MonoMethod*
6814 get_original_method (MonoMethod *method)
6815 {
6816         if (method->wrapper_type == MONO_WRAPPER_NONE)
6817                 return method;
6818
6819         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6820         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6821                 return NULL;
6822
6823         /* in other cases we need to find the original method */
6824         return mono_marshal_method_from_wrapper (method);
6825 }
6826
6827 static void
6828 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
6829 {
6830         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6831         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6832         if (ex)
6833                 emit_throw_exception (cfg, ex);
6834 }
6835
6836 static void
6837 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6838 {
6839         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6840         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6841         if (ex)
6842                 emit_throw_exception (cfg, ex);
6843 }
6844
6845 /*
6846  * Check that the IL instructions at ip are the array initialization
6847  * sequence and return the pointer to the data and the size.
6848  */
6849 static const char*
6850 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6851 {
6852         /*
6853          * newarr[System.Int32]
6854          * dup
6855          * ldtoken field valuetype ...
6856          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6857          */
6858         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6859                 MonoError error;
6860                 guint32 token = read32 (ip + 7);
6861                 guint32 field_token = read32 (ip + 2);
6862                 guint32 field_index = field_token & 0xffffff;
6863                 guint32 rva;
6864                 const char *data_ptr;
6865                 int size = 0;
6866                 MonoMethod *cmethod;
6867                 MonoClass *dummy_class;
6868                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
6869                 int dummy_align;
6870
6871                 if (!field) {
6872                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6873                         return NULL;
6874                 }
6875
6876                 *out_field_token = field_token;
6877
6878                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6879                 if (!cmethod)
6880                         return NULL;
6881                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6882                         return NULL;
6883                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6884                 case MONO_TYPE_BOOLEAN:
6885                 case MONO_TYPE_I1:
6886                 case MONO_TYPE_U1:
6887                         size = 1; break;
6888                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6889 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6890                 case MONO_TYPE_CHAR:
6891                 case MONO_TYPE_I2:
6892                 case MONO_TYPE_U2:
6893                         size = 2; break;
6894                 case MONO_TYPE_I4:
6895                 case MONO_TYPE_U4:
6896                 case MONO_TYPE_R4:
6897                         size = 4; break;
6898                 case MONO_TYPE_R8:
6899                 case MONO_TYPE_I8:
6900                 case MONO_TYPE_U8:
6901                         size = 8; break;
6902 #endif
6903                 default:
6904                         return NULL;
6905                 }
6906                 size *= len;
6907                 if (size > mono_type_size (field->type, &dummy_align))
6908                     return NULL;
6909                 *out_size = size;
6910                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6911                 if (!image_is_dynamic (method->klass->image)) {
6912                         field_index = read32 (ip + 2) & 0xffffff;
6913                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6914                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6915                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6916                         /* for aot code we do the lookup on load */
6917                         if (aot && data_ptr)
6918                                 return (const char *)GUINT_TO_POINTER (rva);
6919                 } else {
6920                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6921                         g_assert (!aot);
6922                         data_ptr = mono_field_get_data (field);
6923                 }
6924                 return data_ptr;
6925         }
6926         return NULL;
6927 }
6928
6929 static void
6930 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6931 {
6932         MonoError error;
6933         char *method_fname = mono_method_full_name (method, TRUE);
6934         char *method_code;
6935         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
6936
6937         if (!header) {
6938                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
6939                 mono_error_cleanup (&error);
6940         } else if (header->code_size == 0)
6941                 method_code = g_strdup ("method body is empty.");
6942         else
6943                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6944         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
6945         g_free (method_fname);
6946         g_free (method_code);
6947         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6948 }
6949
6950 static void
6951 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6952 {
6953         MonoInst *ins;
6954         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6955         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6956                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6957                 /* Optimize reg-reg moves away */
6958                 /* 
6959                  * Can't optimize other opcodes, since sp[0] might point to
6960                  * the last ins of a decomposed opcode.
6961                  */
6962                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6963         } else {
6964                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6965         }
6966 }
6967
6968 /*
6969  * ldloca inhibits many optimizations so try to get rid of it in common
6970  * cases.
6971  */
6972 static inline unsigned char *
6973 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6974 {
6975         int local, token;
6976         MonoClass *klass;
6977         MonoType *type;
6978
6979         if (size == 1) {
6980                 local = ip [1];
6981                 ip += 2;
6982         } else {
6983                 local = read16 (ip + 2);
6984                 ip += 4;
6985         }
6986         
6987         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6988                 /* From the INITOBJ case */
6989                 token = read32 (ip + 2);
6990                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6991                 CHECK_TYPELOAD (klass);
6992                 type = mini_get_underlying_type (&klass->byval_arg);
6993                 emit_init_local (cfg, local, type, TRUE);
6994                 return ip + 6;
6995         }
6996  exception_exit:
6997         return NULL;
6998 }
6999
7000 static MonoInst*
7001 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7002 {
7003         MonoInst *icall_args [16];
7004         MonoInst *call_target, *ins, *vtable_ins;
7005         int arg_reg, this_reg, vtable_reg;
7006         gboolean is_iface = mono_class_is_interface (cmethod->klass);
7007         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7008         gboolean variant_iface = FALSE;
7009         guint32 slot;
7010         int offset;
7011         gboolean special_array_interface = cmethod->klass->is_array_special_interface;
7012
7013         /*
7014          * In llvm-only mode, vtables contain function descriptors instead of
7015          * method addresses/trampolines.
7016          */
7017         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7018
7019         if (is_iface)
7020                 slot = mono_method_get_imt_slot (cmethod);
7021         else
7022                 slot = mono_method_get_vtable_index (cmethod);
7023
7024         this_reg = sp [0]->dreg;
7025
7026         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7027                 variant_iface = TRUE;
7028
7029         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7030                 /*
7031                  * The simplest case, a normal virtual call.
7032                  */
7033                 int slot_reg = alloc_preg (cfg);
7034                 int addr_reg = alloc_preg (cfg);
7035                 int arg_reg = alloc_preg (cfg);
7036                 MonoBasicBlock *non_null_bb;
7037
7038                 vtable_reg = alloc_preg (cfg);
7039                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7040                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7041
7042                 /* Load the vtable slot, which contains a function descriptor. */
7043                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7044
7045                 NEW_BBLOCK (cfg, non_null_bb);
7046
7047                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7048                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7049                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7050
7051                 /* Slow path */
7052                 // FIXME: Make the wrapper use the preserveall cconv
7053                 // FIXME: Use one icall per slot for small slot numbers ?
7054                 icall_args [0] = vtable_ins;
7055                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7056                 /* Make the icall return the vtable slot value to save some code space */
7057                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7058                 ins->dreg = slot_reg;
7059                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7060
7061                 /* Fastpath */
7062                 MONO_START_BB (cfg, non_null_bb);
7063                 /* Load the address + arg from the vtable slot */
7064                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7065                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7066
7067                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7068         }
7069
7070         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt && !special_array_interface) {
7071                 /*
7072                  * A simple interface call
7073                  *
7074                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7075                  * The imt slot contains a function descriptor for a runtime function + arg.
7076                  */
7077                 int slot_reg = alloc_preg (cfg);
7078                 int addr_reg = alloc_preg (cfg);
7079                 int arg_reg = alloc_preg (cfg);
7080                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7081
7082                 vtable_reg = alloc_preg (cfg);
7083                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7084                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7085
7086                 /*
7087                  * The slot is already initialized when the vtable is created so there is no need
7088                  * to check it here.
7089                  */
7090
7091                 /* Load the imt slot, which contains a function descriptor. */
7092                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7093
7094                 /* Load the address + arg of the imt thunk from the imt slot */
7095                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7096                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7097                 /*
7098                  * IMT thunks in llvm-only mode are C functions which take an info argument
7099                  * plus the imt method and return the ftndesc to call.
7100                  */
7101                 icall_args [0] = thunk_arg_ins;
7102                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7103                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7104                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7105
7106                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7107         }
7108
7109         if ((fsig->generic_param_count || variant_iface || special_array_interface) && !is_gsharedvt) {
7110                 /*
7111                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7112                  * dynamically extended as more instantiations are discovered.
7113                  * This handles generic virtual methods both on classes and interfaces.
7114                  */
7115                 int slot_reg = alloc_preg (cfg);
7116                 int addr_reg = alloc_preg (cfg);
7117                 int arg_reg = alloc_preg (cfg);
7118                 int ftndesc_reg = alloc_preg (cfg);
7119                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7120                 MonoBasicBlock *slowpath_bb, *end_bb;
7121
7122                 NEW_BBLOCK (cfg, slowpath_bb);
7123                 NEW_BBLOCK (cfg, end_bb);
7124
7125                 vtable_reg = alloc_preg (cfg);
7126                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7127                 if (is_iface)
7128                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7129                 else
7130                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7131
7132                 /* Load the slot, which contains a function descriptor. */
7133                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7134
7135                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7136                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7137                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7138                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7139
7140                 /* Fastpath */
7141                 /* Same as with iface calls */
7142                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7143                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7144                 icall_args [0] = thunk_arg_ins;
7145                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7146                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7147                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7148                 ftndesc_ins->dreg = ftndesc_reg;
7149                 /*
7150                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7151                  * they don't know about yet. Fall back to the slowpath in that case.
7152                  */
7153                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7154                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7155
7156                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7157
7158                 /* Slowpath */
7159                 MONO_START_BB (cfg, slowpath_bb);
7160                 icall_args [0] = vtable_ins;
7161                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7162                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7163                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7164                 if (is_iface)
7165                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7166                 else
7167                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7168                 ftndesc_ins->dreg = ftndesc_reg;
7169                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7170
7171                 /* Common case */
7172                 MONO_START_BB (cfg, end_bb);
7173                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7174         }
7175
7176         /*
7177          * Non-optimized cases
7178          */
7179         icall_args [0] = sp [0];
7180         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7181
7182         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7183                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7184
7185         arg_reg = alloc_preg (cfg);
7186         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7187         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7188
7189         g_assert (is_gsharedvt);
7190         if (is_iface)
7191                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7192         else
7193                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7194
7195         /*
7196          * Pass the extra argument even if the callee doesn't receive it, most
7197          * calling conventions allow this.
7198          */
7199         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7200 }
7201
7202 static gboolean
7203 is_exception_class (MonoClass *klass)
7204 {
7205         while (klass) {
7206                 if (klass == mono_defaults.exception_class)
7207                         return TRUE;
7208                 klass = klass->parent;
7209         }
7210         return FALSE;
7211 }
7212
7213 /*
7214  * is_jit_optimizer_disabled:
7215  *
7216  *   Determine whenever M's assembly has a DebuggableAttribute with the
7217  * IsJITOptimizerDisabled flag set.
7218  */
7219 static gboolean
7220 is_jit_optimizer_disabled (MonoMethod *m)
7221 {
7222         MonoError error;
7223         MonoAssembly *ass = m->klass->image->assembly;
7224         MonoCustomAttrInfo* attrs;
7225         MonoClass *klass;
7226         int i;
7227         gboolean val = FALSE;
7228
7229         g_assert (ass);
7230         if (ass->jit_optimizer_disabled_inited)
7231                 return ass->jit_optimizer_disabled;
7232
7233         klass = mono_class_try_get_debuggable_attribute_class ();
7234
7235         if (!klass) {
7236                 /* Linked away */
7237                 ass->jit_optimizer_disabled = FALSE;
7238                 mono_memory_barrier ();
7239                 ass->jit_optimizer_disabled_inited = TRUE;
7240                 return FALSE;
7241         }
7242
7243         attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
7244         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7245         if (attrs) {
7246                 for (i = 0; i < attrs->num_attrs; ++i) {
7247                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7248                         const gchar *p;
7249                         MonoMethodSignature *sig;
7250
7251                         if (!attr->ctor || attr->ctor->klass != klass)
7252                                 continue;
7253                         /* Decode the attribute. See reflection.c */
7254                         p = (const char*)attr->data;
7255                         g_assert (read16 (p) == 0x0001);
7256                         p += 2;
7257
7258                         // FIXME: Support named parameters
7259                         sig = mono_method_signature (attr->ctor);
7260                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7261                                 continue;
7262                         /* Two boolean arguments */
7263                         p ++;
7264                         val = *p;
7265                 }
7266                 mono_custom_attrs_free (attrs);
7267         }
7268
7269         ass->jit_optimizer_disabled = val;
7270         mono_memory_barrier ();
7271         ass->jit_optimizer_disabled_inited = TRUE;
7272
7273         return val;
7274 }
7275
7276 static gboolean
7277 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7278 {
7279         gboolean supported_tail_call;
7280         int i;
7281
7282         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7283
7284         for (i = 0; i < fsig->param_count; ++i) {
7285                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7286                         /* These can point to the current method's stack */
7287                         supported_tail_call = FALSE;
7288         }
7289         if (fsig->hasthis && cmethod->klass->valuetype)
7290                 /* this might point to the current method's stack */
7291                 supported_tail_call = FALSE;
7292         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7293                 supported_tail_call = FALSE;
7294         if (cfg->method->save_lmf)
7295                 supported_tail_call = FALSE;
7296         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7297                 supported_tail_call = FALSE;
7298         if (call_opcode != CEE_CALL)
7299                 supported_tail_call = FALSE;
7300
7301         /* Debugging support */
7302 #if 0
7303         if (supported_tail_call) {
7304                 if (!mono_debug_count ())
7305                         supported_tail_call = FALSE;
7306         }
7307 #endif
7308
7309         return supported_tail_call;
7310 }
7311
7312 /*
7313  * handle_ctor_call:
7314  *
7315  *   Handle calls made to ctors from NEWOBJ opcodes.
7316  */
7317 static void
7318 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7319                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7320 {
7321         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7322
7323         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7324                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7325                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7326                         mono_class_vtable (cfg->domain, cmethod->klass);
7327                         CHECK_TYPELOAD (cmethod->klass);
7328
7329                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7330                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7331                 } else {
7332                         if (context_used) {
7333                                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
7334                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7335                         } else {
7336                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7337
7338                                 CHECK_TYPELOAD (cmethod->klass);
7339                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7340                         }
7341                 }
7342         }
7343
7344         /* Avoid virtual calls to ctors if possible */
7345         if (mono_class_is_marshalbyref (cmethod->klass))
7346                 callvirt_this_arg = sp [0];
7347
7348         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7349                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7350                 CHECK_CFG_EXCEPTION;
7351         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7352                            mono_method_check_inlining (cfg, cmethod) &&
7353                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7354                 int costs;
7355
7356                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7357                         cfg->real_offset += 5;
7358
7359                         *inline_costs += costs - 5;
7360                 } else {
7361                         INLINE_FAILURE ("inline failure");
7362                         // FIXME-VT: Clean this up
7363                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7364                                 GSHAREDVT_FAILURE(*ip);
7365                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7366                 }
7367         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7368                 MonoInst *addr;
7369
7370                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7371
7372                 if (cfg->llvm_only) {
7373                         // FIXME: Avoid initializing vtable_arg
7374                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7375                 } else {
7376                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7377                 }
7378         } else if (context_used &&
7379                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7380                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7381                 MonoInst *cmethod_addr;
7382
7383                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7384
7385                 if (cfg->llvm_only) {
7386                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
7387                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7388                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7389                 } else {
7390                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7391                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7392
7393                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7394                 }
7395         } else {
7396                 INLINE_FAILURE ("ctor call");
7397                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7398                                                                                   callvirt_this_arg, NULL, vtable_arg);
7399         }
7400  exception_exit:
7401         return;
7402 }
7403
7404 static void
7405 emit_setret (MonoCompile *cfg, MonoInst *val)
7406 {
7407         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7408         MonoInst *ins;
7409
7410         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7411                 MonoInst *ret_addr;
7412
7413                 if (!cfg->vret_addr) {
7414                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7415                 } else {
7416                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7417
7418                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7419                         ins->klass = mono_class_from_mono_type (ret_type);
7420                 }
7421         } else {
7422 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7423                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7424                         MonoInst *iargs [1];
7425                         MonoInst *conv;
7426
7427                         iargs [0] = val;
7428                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7429                         mono_arch_emit_setret (cfg, cfg->method, conv);
7430                 } else {
7431                         mono_arch_emit_setret (cfg, cfg->method, val);
7432                 }
7433 #else
7434                 mono_arch_emit_setret (cfg, cfg->method, val);
7435 #endif
7436         }
7437 }
7438
7439 /*
7440  * mono_method_to_ir:
7441  *
7442  * Translate the .net IL into linear IR.
7443  *
7444  * @start_bblock: if not NULL, the starting basic block, used during inlining.
7445  * @end_bblock: if not NULL, the ending basic block, used during inlining.
7446  * @return_var: if not NULL, the place where the return value is stored, used during inlining.   
7447  * @inline_args: if not NULL, contains the arguments to the inline call
7448  * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise.
7449  * @is_virtual_call: whether this method is being called as a result of a call to callvirt
7450  *
7451  * This method is used to turn ECMA IL into Mono's internal Linear IR
7452  * reprensetation.  It is used both for entire methods, as well as
7453  * inlining existing methods.  In the former case, the @start_bblock,
7454  * @end_bblock, @return_var, @inline_args are all set to NULL, and the
7455  * inline_offset is set to zero.
7456  * 
7457  * Returns: the inline cost, or -1 if there was an error processing this method.
7458  */
7459 int
7460 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7461                    MonoInst *return_var, MonoInst **inline_args, 
7462                    guint inline_offset, gboolean is_virtual_call)
7463 {
7464         MonoError error;
7465         MonoInst *ins, **sp, **stack_start;
7466         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7467         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7468         MonoMethod *cmethod, *method_definition;
7469         MonoInst **arg_array;
7470         MonoMethodHeader *header;
7471         MonoImage *image;
7472         guint32 token, ins_flag;
7473         MonoClass *klass;
7474         MonoClass *constrained_class = NULL;
7475         unsigned char *ip, *end, *target, *err_pos;
7476         MonoMethodSignature *sig;
7477         MonoGenericContext *generic_context = NULL;
7478         MonoGenericContainer *generic_container = NULL;
7479         MonoType **param_types;
7480         int i, n, start_new_bblock, dreg;
7481         int num_calls = 0, inline_costs = 0;
7482         int breakpoint_id = 0;
7483         guint num_args;
7484         GSList *class_inits = NULL;
7485         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7486         int context_used;
7487         gboolean init_locals, seq_points, skip_dead_blocks;
7488         gboolean sym_seq_points = FALSE;
7489         MonoDebugMethodInfo *minfo;
7490         MonoBitSet *seq_point_locs = NULL;
7491         MonoBitSet *seq_point_set_locs = NULL;
7492
7493         cfg->disable_inline = is_jit_optimizer_disabled (method);
7494
7495         /* serialization and xdomain stuff may need access to private fields and methods */
7496         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7497         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7498         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7499         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7500         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7501         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7502
7503         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7504         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7505         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7506         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7507         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7508
7509         image = method->klass->image;
7510         header = mono_method_get_header_checked (method, &cfg->error);
7511         if (!header) {
7512                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7513                 goto exception_exit;
7514         } else {
7515                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7516         }
7517
7518         generic_container = mono_method_get_generic_container (method);
7519         sig = mono_method_signature (method);
7520         num_args = sig->hasthis + sig->param_count;
7521         ip = (unsigned char*)header->code;
7522         cfg->cil_start = ip;
7523         end = ip + header->code_size;
7524         cfg->stat_cil_code_size += header->code_size;
7525
7526         seq_points = cfg->gen_seq_points && cfg->method == method;
7527
7528         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7529                 /* We could hit a seq point before attaching to the JIT (#8338) */
7530                 seq_points = FALSE;
7531         }
7532
7533         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7534                 minfo = mono_debug_lookup_method (method);
7535                 if (minfo) {
7536                         MonoSymSeqPoint *sps;
7537                         int i, n_il_offsets;
7538
7539                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7540                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7541                         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);
7542                         sym_seq_points = TRUE;
7543                         for (i = 0; i < n_il_offsets; ++i) {
7544                                 if (sps [i].il_offset < header->code_size)
7545                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7546                         }
7547                         g_free (sps);
7548
7549                         MonoDebugMethodAsyncInfo* asyncMethod = mono_debug_lookup_method_async_debug_info (method);
7550                         if (asyncMethod) {
7551                                 for (i = 0; asyncMethod != NULL && i < asyncMethod->num_awaits; i++)
7552                                 {
7553                                         mono_bitset_set_fast (seq_point_locs, asyncMethod->resume_offsets[i]);
7554                                         mono_bitset_set_fast (seq_point_locs, asyncMethod->yield_offsets[i]);
7555                                 }
7556                                 mono_debug_free_method_async_debug_info (asyncMethod);
7557                         }
7558                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7559                         /* Methods without line number info like auto-generated property accessors */
7560                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7561                         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);
7562                         sym_seq_points = TRUE;
7563                 }
7564         }
7565
7566         /* 
7567          * Methods without init_locals set could cause asserts in various passes
7568          * (#497220). To work around this, we emit dummy initialization opcodes
7569          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7570          * on some platforms.
7571          */
7572         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
7573                 init_locals = header->init_locals;
7574         else
7575                 init_locals = TRUE;
7576
7577         method_definition = method;
7578         while (method_definition->is_inflated) {
7579                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7580                 method_definition = imethod->declaring;
7581         }
7582
7583         /* SkipVerification is not allowed if core-clr is enabled */
7584         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7585                 dont_verify = TRUE;
7586                 dont_verify_stloc = TRUE;
7587         }
7588
7589         if (sig->is_inflated)
7590                 generic_context = mono_method_get_context (method);
7591         else if (generic_container)
7592                 generic_context = &generic_container->context;
7593         cfg->generic_context = generic_context;
7594
7595         if (!cfg->gshared)
7596                 g_assert (!sig->has_type_parameters);
7597
7598         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7599                 g_assert (method->is_inflated);
7600                 g_assert (mono_method_get_context (method)->method_inst);
7601         }
7602         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7603                 g_assert (sig->generic_param_count);
7604
7605         if (cfg->method == method) {
7606                 cfg->real_offset = 0;
7607         } else {
7608                 cfg->real_offset = inline_offset;
7609         }
7610
7611         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7612         cfg->cil_offset_to_bb_len = header->code_size;
7613
7614         cfg->current_method = method;
7615
7616         if (cfg->verbose_level > 2)
7617                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7618
7619         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7620         if (sig->hasthis)
7621                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7622         for (n = 0; n < sig->param_count; ++n)
7623                 param_types [n + sig->hasthis] = sig->params [n];
7624         cfg->arg_types = param_types;
7625
7626         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7627         if (cfg->method == method) {
7628
7629                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7630                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7631
7632                 /* ENTRY BLOCK */
7633                 NEW_BBLOCK (cfg, start_bblock);
7634                 cfg->bb_entry = start_bblock;
7635                 start_bblock->cil_code = NULL;
7636                 start_bblock->cil_length = 0;
7637
7638                 /* EXIT BLOCK */
7639                 NEW_BBLOCK (cfg, end_bblock);
7640                 cfg->bb_exit = end_bblock;
7641                 end_bblock->cil_code = NULL;
7642                 end_bblock->cil_length = 0;
7643                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7644                 g_assert (cfg->num_bblocks == 2);
7645
7646                 arg_array = cfg->args;
7647
7648                 if (header->num_clauses) {
7649                         cfg->spvars = g_hash_table_new (NULL, NULL);
7650                         cfg->exvars = g_hash_table_new (NULL, NULL);
7651                 }
7652                 /* handle exception clauses */
7653                 for (i = 0; i < header->num_clauses; ++i) {
7654                         MonoBasicBlock *try_bb;
7655                         MonoExceptionClause *clause = &header->clauses [i];
7656                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7657
7658                         try_bb->real_offset = clause->try_offset;
7659                         try_bb->try_start = TRUE;
7660                         try_bb->region = ((i + 1) << 8) | clause->flags;
7661                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7662                         tblock->real_offset = clause->handler_offset;
7663                         tblock->flags |= BB_EXCEPTION_HANDLER;
7664
7665                         /*
7666                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7667                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7668                          */
7669                         if (COMPILE_LLVM (cfg))
7670                                 link_bblock (cfg, try_bb, tblock);
7671
7672                         if (*(ip + clause->handler_offset) == CEE_POP)
7673                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7674
7675                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7676                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7677                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7678                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7679                                 MONO_ADD_INS (tblock, ins);
7680
7681                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
7682                                         /* finally clauses already have a seq point */
7683                                         /* seq points for filter clauses are emitted below */
7684                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7685                                         MONO_ADD_INS (tblock, ins);
7686                                 }
7687
7688                                 /* todo: is a fault block unsafe to optimize? */
7689                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7690                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7691                         }
7692
7693                         /*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);
7694                           while (p < end) {
7695                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7696                           }*/
7697                         /* catch and filter blocks get the exception object on the stack */
7698                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7699                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7700
7701                                 /* mostly like handle_stack_args (), but just sets the input args */
7702                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7703                                 tblock->in_scount = 1;
7704                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7705                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7706
7707                                 cfg->cbb = tblock;
7708
7709 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7710                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7711                                 if (!cfg->compile_llvm) {
7712                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7713                                         ins->dreg = tblock->in_stack [0]->dreg;
7714                                         MONO_ADD_INS (tblock, ins);
7715                                 }
7716 #else
7717                                 MonoInst *dummy_use;
7718
7719                                 /* 
7720                                  * Add a dummy use for the exvar so its liveness info will be
7721                                  * correct.
7722                                  */
7723                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7724 #endif
7725
7726                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7727                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7728                                         MONO_ADD_INS (tblock, ins);
7729                                 }
7730                                 
7731                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7732                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7733                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7734                                         tblock->real_offset = clause->data.filter_offset;
7735                                         tblock->in_scount = 1;
7736                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7737                                         /* The filter block shares the exvar with the handler block */
7738                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7739                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7740                                         MONO_ADD_INS (tblock, ins);
7741                                 }
7742                         }
7743
7744                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7745                                         clause->data.catch_class &&
7746                                         cfg->gshared &&
7747                                         mono_class_check_context_used (clause->data.catch_class)) {
7748                                 /*
7749                                  * In shared generic code with catch
7750                                  * clauses containing type variables
7751                                  * the exception handling code has to
7752                                  * be able to get to the rgctx.
7753                                  * Therefore we have to make sure that
7754                                  * the vtable/mrgctx argument (for
7755                                  * static or generic methods) or the
7756                                  * "this" argument (for non-static
7757                                  * methods) are live.
7758                                  */
7759                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7760                                                 mini_method_get_context (method)->method_inst ||
7761                                                 method->klass->valuetype) {
7762                                         mono_get_vtable_var (cfg);
7763                                 } else {
7764                                         MonoInst *dummy_use;
7765
7766                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7767                                 }
7768                         }
7769                 }
7770         } else {
7771                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7772                 cfg->cbb = start_bblock;
7773                 cfg->args = arg_array;
7774                 mono_save_args (cfg, sig, inline_args);
7775         }
7776
7777         /* FIRST CODE BLOCK */
7778         NEW_BBLOCK (cfg, tblock);
7779         tblock->cil_code = ip;
7780         cfg->cbb = tblock;
7781         cfg->ip = ip;
7782
7783         ADD_BBLOCK (cfg, tblock);
7784
7785         if (cfg->method == method) {
7786                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7787                 if (breakpoint_id) {
7788                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7789                         MONO_ADD_INS (cfg->cbb, ins);
7790                 }
7791         }
7792
7793         /* we use a separate basic block for the initialization code */
7794         NEW_BBLOCK (cfg, init_localsbb);
7795         if (cfg->method == method)
7796                 cfg->bb_init = init_localsbb;
7797         init_localsbb->real_offset = cfg->real_offset;
7798         start_bblock->next_bb = init_localsbb;
7799         init_localsbb->next_bb = cfg->cbb;
7800         link_bblock (cfg, start_bblock, init_localsbb);
7801         link_bblock (cfg, init_localsbb, cfg->cbb);
7802                 
7803         cfg->cbb = init_localsbb;
7804
7805         if (cfg->gsharedvt && cfg->method == method) {
7806                 MonoGSharedVtMethodInfo *info;
7807                 MonoInst *var, *locals_var;
7808                 int dreg;
7809
7810                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7811                 info->method = cfg->method;
7812                 info->count_entries = 16;
7813                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7814                 cfg->gsharedvt_info = info;
7815
7816                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7817                 /* prevent it from being register allocated */
7818                 //var->flags |= MONO_INST_VOLATILE;
7819                 cfg->gsharedvt_info_var = var;
7820
7821                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7822                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7823
7824                 /* Allocate locals */
7825                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7826                 /* prevent it from being register allocated */
7827                 //locals_var->flags |= MONO_INST_VOLATILE;
7828                 cfg->gsharedvt_locals_var = locals_var;
7829
7830                 dreg = alloc_ireg (cfg);
7831                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7832
7833                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7834                 ins->dreg = locals_var->dreg;
7835                 ins->sreg1 = dreg;
7836                 MONO_ADD_INS (cfg->cbb, ins);
7837                 cfg->gsharedvt_locals_var_ins = ins;
7838                 
7839                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7840                 /*
7841                 if (init_locals)
7842                         ins->flags |= MONO_INST_INIT;
7843                 */
7844         }
7845
7846         if (mono_security_core_clr_enabled ()) {
7847                 /* check if this is native code, e.g. an icall or a p/invoke */
7848                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7849                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7850                         if (wrapped) {
7851                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7852                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7853
7854                                 /* if this ia a native call then it can only be JITted from platform code */
7855                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7856                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7857                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7858                                                         mono_get_exception_method_access ();
7859                                                 emit_throw_exception (cfg, ex);
7860                                         }
7861                                 }
7862                         }
7863                 }
7864         }
7865
7866         CHECK_CFG_EXCEPTION;
7867
7868         if (header->code_size == 0)
7869                 UNVERIFIED;
7870
7871         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7872                 ip = err_pos;
7873                 UNVERIFIED;
7874         }
7875
7876         if (cfg->method == method)
7877                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
7878
7879         for (n = 0; n < header->num_locals; ++n) {
7880                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7881                         UNVERIFIED;
7882         }
7883         class_inits = NULL;
7884
7885         /* We force the vtable variable here for all shared methods
7886            for the possibility that they might show up in a stack
7887            trace where their exact instantiation is needed. */
7888         if (cfg->gshared && method == cfg->method) {
7889                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7890                                 mini_method_get_context (method)->method_inst ||
7891                                 method->klass->valuetype) {
7892                         mono_get_vtable_var (cfg);
7893                 } else {
7894                         /* FIXME: Is there a better way to do this?
7895                            We need the variable live for the duration
7896                            of the whole method. */
7897                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7898                 }
7899         }
7900
7901         /* add a check for this != NULL to inlined methods */
7902         if (is_virtual_call) {
7903                 MonoInst *arg_ins;
7904
7905                 NEW_ARGLOAD (cfg, arg_ins, 0);
7906                 MONO_ADD_INS (cfg->cbb, arg_ins);
7907                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7908         }
7909
7910         skip_dead_blocks = !dont_verify;
7911         if (skip_dead_blocks) {
7912                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
7913                 CHECK_CFG_ERROR;
7914                 g_assert (bb);
7915         }
7916
7917         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7918         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7919
7920         ins_flag = 0;
7921         start_new_bblock = 0;
7922         while (ip < end) {
7923                 if (cfg->method == method)
7924                         cfg->real_offset = ip - header->code;
7925                 else
7926                         cfg->real_offset = inline_offset;
7927                 cfg->ip = ip;
7928
7929                 context_used = 0;
7930
7931                 if (start_new_bblock) {
7932                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
7933                         if (start_new_bblock == 2) {
7934                                 g_assert (ip == tblock->cil_code);
7935                         } else {
7936                                 GET_BBLOCK (cfg, tblock, ip);
7937                         }
7938                         cfg->cbb->next_bb = tblock;
7939                         cfg->cbb = tblock;
7940                         start_new_bblock = 0;
7941                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
7942                                 if (cfg->verbose_level > 3)
7943                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7944                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7945                                 *sp++ = ins;
7946                         }
7947                         if (class_inits)
7948                                 g_slist_free (class_inits);
7949                         class_inits = NULL;
7950                 } else {
7951                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
7952                                 link_bblock (cfg, cfg->cbb, tblock);
7953                                 if (sp != stack_start) {
7954                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7955                                         sp = stack_start;
7956                                         CHECK_UNVERIFIABLE (cfg);
7957                                 }
7958                                 cfg->cbb->next_bb = tblock;
7959                                 cfg->cbb = tblock;
7960                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
7961                                         if (cfg->verbose_level > 3)
7962                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7963                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7964                                         *sp++ = ins;
7965                                 }
7966                                 g_slist_free (class_inits);
7967                                 class_inits = NULL;
7968                         }
7969                 }
7970
7971                 if (skip_dead_blocks) {
7972                         int ip_offset = ip - header->code;
7973
7974                         if (ip_offset == bb->end)
7975                                 bb = bb->next;
7976
7977                         if (bb->dead) {
7978                                 int op_size = mono_opcode_size (ip, end);
7979                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7980
7981                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7982
7983                                 if (ip_offset + op_size == bb->end) {
7984                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7985                                         MONO_ADD_INS (cfg->cbb, ins);
7986                                         start_new_bblock = 1;
7987                                 }
7988
7989                                 ip += op_size;
7990                                 continue;
7991                         }
7992                 }
7993                 /*
7994                  * Sequence points are points where the debugger can place a breakpoint.
7995                  * Currently, we generate these automatically at points where the IL
7996                  * stack is empty.
7997                  */
7998                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7999                         /*
8000                          * Make methods interruptable at the beginning, and at the targets of
8001                          * backward branches.
8002                          * Also, do this at the start of every bblock in methods with clauses too,
8003                          * to be able to handle instructions with inprecise control flow like
8004                          * throw/endfinally.
8005                          * Backward branches are handled at the end of method-to-ir ().
8006                          */
8007                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8008                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8009
8010                         /* Avoid sequence points on empty IL like .volatile */
8011                         // FIXME: Enable this
8012                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8013                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8014                         if ((sp != stack_start) && !sym_seq_point)
8015                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8016                         MONO_ADD_INS (cfg->cbb, ins);
8017
8018                         if (sym_seq_points)
8019                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8020                 }
8021
8022                 cfg->cbb->real_offset = cfg->real_offset;
8023
8024                 if ((cfg->method == method) && cfg->coverage_info) {
8025                         guint32 cil_offset = ip - header->code;
8026                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8027
8028                         /* TODO: Use an increment here */
8029 #if defined(TARGET_X86)
8030                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8031                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8032                         ins->inst_imm = 1;
8033                         MONO_ADD_INS (cfg->cbb, ins);
8034 #else
8035                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8036                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8037 #endif
8038                 }
8039
8040                 if (cfg->verbose_level > 3)
8041                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8042
8043                 switch (*ip) {
8044                 case CEE_NOP:
8045                         if (seq_points && !sym_seq_points && sp != stack_start) {
8046                                 /*
8047                                  * The C# compiler uses these nops to notify the JIT that it should
8048                                  * insert seq points.
8049                                  */
8050                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8051                                 MONO_ADD_INS (cfg->cbb, ins);
8052                         }
8053                         if (cfg->keep_cil_nops)
8054                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8055                         else
8056                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8057                         ip++;
8058                         MONO_ADD_INS (cfg->cbb, ins);
8059                         break;
8060                 case CEE_BREAK:
8061                         if (should_insert_brekpoint (cfg->method)) {
8062                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8063                         } else {
8064                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8065                         }
8066                         ip++;
8067                         MONO_ADD_INS (cfg->cbb, ins);
8068                         break;
8069                 case CEE_LDARG_0:
8070                 case CEE_LDARG_1:
8071                 case CEE_LDARG_2:
8072                 case CEE_LDARG_3:
8073                         CHECK_STACK_OVF (1);
8074                         n = (*ip)-CEE_LDARG_0;
8075                         CHECK_ARG (n);
8076                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8077                         ip++;
8078                         *sp++ = ins;
8079                         break;
8080                 case CEE_LDLOC_0:
8081                 case CEE_LDLOC_1:
8082                 case CEE_LDLOC_2:
8083                 case CEE_LDLOC_3:
8084                         CHECK_STACK_OVF (1);
8085                         n = (*ip)-CEE_LDLOC_0;
8086                         CHECK_LOCAL (n);
8087                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8088                         ip++;
8089                         *sp++ = ins;
8090                         break;
8091                 case CEE_STLOC_0:
8092                 case CEE_STLOC_1:
8093                 case CEE_STLOC_2:
8094                 case CEE_STLOC_3: {
8095                         CHECK_STACK (1);
8096                         n = (*ip)-CEE_STLOC_0;
8097                         CHECK_LOCAL (n);
8098                         --sp;
8099                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8100                                 UNVERIFIED;
8101                         emit_stloc_ir (cfg, sp, header, n);
8102                         ++ip;
8103                         inline_costs += 1;
8104                         break;
8105                         }
8106                 case CEE_LDARG_S:
8107                         CHECK_OPSIZE (2);
8108                         CHECK_STACK_OVF (1);
8109                         n = ip [1];
8110                         CHECK_ARG (n);
8111                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8112                         *sp++ = ins;
8113                         ip += 2;
8114                         break;
8115                 case CEE_LDARGA_S:
8116                         CHECK_OPSIZE (2);
8117                         CHECK_STACK_OVF (1);
8118                         n = ip [1];
8119                         CHECK_ARG (n);
8120                         NEW_ARGLOADA (cfg, ins, n);
8121                         MONO_ADD_INS (cfg->cbb, ins);
8122                         *sp++ = ins;
8123                         ip += 2;
8124                         break;
8125                 case CEE_STARG_S:
8126                         CHECK_OPSIZE (2);
8127                         CHECK_STACK (1);
8128                         --sp;
8129                         n = ip [1];
8130                         CHECK_ARG (n);
8131                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8132                                 UNVERIFIED;
8133                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8134                         ip += 2;
8135                         break;
8136                 case CEE_LDLOC_S:
8137                         CHECK_OPSIZE (2);
8138                         CHECK_STACK_OVF (1);
8139                         n = ip [1];
8140                         CHECK_LOCAL (n);
8141                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8142                         *sp++ = ins;
8143                         ip += 2;
8144                         break;
8145                 case CEE_LDLOCA_S: {
8146                         unsigned char *tmp_ip;
8147                         CHECK_OPSIZE (2);
8148                         CHECK_STACK_OVF (1);
8149                         CHECK_LOCAL (ip [1]);
8150
8151                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8152                                 ip = tmp_ip;
8153                                 inline_costs += 1;
8154                                 break;
8155                         }
8156
8157                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8158                         *sp++ = ins;
8159                         ip += 2;
8160                         break;
8161                 }
8162                 case CEE_STLOC_S:
8163                         CHECK_OPSIZE (2);
8164                         CHECK_STACK (1);
8165                         --sp;
8166                         CHECK_LOCAL (ip [1]);
8167                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8168                                 UNVERIFIED;
8169                         emit_stloc_ir (cfg, sp, header, ip [1]);
8170                         ip += 2;
8171                         inline_costs += 1;
8172                         break;
8173                 case CEE_LDNULL:
8174                         CHECK_STACK_OVF (1);
8175                         EMIT_NEW_PCONST (cfg, ins, NULL);
8176                         ins->type = STACK_OBJ;
8177                         ++ip;
8178                         *sp++ = ins;
8179                         break;
8180                 case CEE_LDC_I4_M1:
8181                         CHECK_STACK_OVF (1);
8182                         EMIT_NEW_ICONST (cfg, ins, -1);
8183                         ++ip;
8184                         *sp++ = ins;
8185                         break;
8186                 case CEE_LDC_I4_0:
8187                 case CEE_LDC_I4_1:
8188                 case CEE_LDC_I4_2:
8189                 case CEE_LDC_I4_3:
8190                 case CEE_LDC_I4_4:
8191                 case CEE_LDC_I4_5:
8192                 case CEE_LDC_I4_6:
8193                 case CEE_LDC_I4_7:
8194                 case CEE_LDC_I4_8:
8195                         CHECK_STACK_OVF (1);
8196                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8197                         ++ip;
8198                         *sp++ = ins;
8199                         break;
8200                 case CEE_LDC_I4_S:
8201                         CHECK_OPSIZE (2);
8202                         CHECK_STACK_OVF (1);
8203                         ++ip;
8204                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8205                         ++ip;
8206                         *sp++ = ins;
8207                         break;
8208                 case CEE_LDC_I4:
8209                         CHECK_OPSIZE (5);
8210                         CHECK_STACK_OVF (1);
8211                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8212                         ip += 5;
8213                         *sp++ = ins;
8214                         break;
8215                 case CEE_LDC_I8:
8216                         CHECK_OPSIZE (9);
8217                         CHECK_STACK_OVF (1);
8218                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8219                         ins->type = STACK_I8;
8220                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8221                         ++ip;
8222                         ins->inst_l = (gint64)read64 (ip);
8223                         MONO_ADD_INS (cfg->cbb, ins);
8224                         ip += 8;
8225                         *sp++ = ins;
8226                         break;
8227                 case CEE_LDC_R4: {
8228                         float *f;
8229                         gboolean use_aotconst = FALSE;
8230
8231 #ifdef TARGET_POWERPC
8232                         /* FIXME: Clean this up */
8233                         if (cfg->compile_aot)
8234                                 use_aotconst = TRUE;
8235 #endif
8236
8237                         /* FIXME: we should really allocate this only late in the compilation process */
8238                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8239                         CHECK_OPSIZE (5);
8240                         CHECK_STACK_OVF (1);
8241
8242                         if (use_aotconst) {
8243                                 MonoInst *cons;
8244                                 int dreg;
8245
8246                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8247
8248                                 dreg = alloc_freg (cfg);
8249                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8250                                 ins->type = cfg->r4_stack_type;
8251                         } else {
8252                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8253                                 ins->type = cfg->r4_stack_type;
8254                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8255                                 ins->inst_p0 = f;
8256                                 MONO_ADD_INS (cfg->cbb, ins);
8257                         }
8258                         ++ip;
8259                         readr4 (ip, f);
8260                         ip += 4;
8261                         *sp++ = ins;                    
8262                         break;
8263                 }
8264                 case CEE_LDC_R8: {
8265                         double *d;
8266                         gboolean use_aotconst = FALSE;
8267
8268 #ifdef TARGET_POWERPC
8269                         /* FIXME: Clean this up */
8270                         if (cfg->compile_aot)
8271                                 use_aotconst = TRUE;
8272 #endif
8273
8274                         /* FIXME: we should really allocate this only late in the compilation process */
8275                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8276                         CHECK_OPSIZE (9);
8277                         CHECK_STACK_OVF (1);
8278
8279                         if (use_aotconst) {
8280                                 MonoInst *cons;
8281                                 int dreg;
8282
8283                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8284
8285                                 dreg = alloc_freg (cfg);
8286                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8287                                 ins->type = STACK_R8;
8288                         } else {
8289                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8290                                 ins->type = STACK_R8;
8291                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8292                                 ins->inst_p0 = d;
8293                                 MONO_ADD_INS (cfg->cbb, ins);
8294                         }
8295                         ++ip;
8296                         readr8 (ip, d);
8297                         ip += 8;
8298                         *sp++ = ins;
8299                         break;
8300                 }
8301                 case CEE_DUP: {
8302                         MonoInst *temp, *store;
8303                         CHECK_STACK (1);
8304                         CHECK_STACK_OVF (1);
8305                         sp--;
8306                         ins = *sp;
8307
8308                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8309                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8310
8311                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8312                         *sp++ = ins;
8313
8314                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8315                         *sp++ = ins;
8316
8317                         ++ip;
8318                         inline_costs += 2;
8319                         break;
8320                 }
8321                 case CEE_POP:
8322                         CHECK_STACK (1);
8323                         ip++;
8324                         --sp;
8325
8326 #ifdef TARGET_X86
8327                         if (sp [0]->type == STACK_R8)
8328                                 /* we need to pop the value from the x86 FP stack */
8329                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8330 #endif
8331                         break;
8332                 case CEE_JMP: {
8333                         MonoCallInst *call;
8334                         MonoMethodSignature *fsig;
8335                         int i, n;
8336
8337                         INLINE_FAILURE ("jmp");
8338                         GSHAREDVT_FAILURE (*ip);
8339
8340                         CHECK_OPSIZE (5);
8341                         if (stack_start != sp)
8342                                 UNVERIFIED;
8343                         token = read32 (ip + 1);
8344                         /* FIXME: check the signature matches */
8345                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8346                         CHECK_CFG_ERROR;
8347  
8348                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8349                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8350
8351                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8352
8353                         fsig = mono_method_signature (cmethod);
8354                         n = fsig->param_count + fsig->hasthis;
8355                         if (cfg->llvm_only) {
8356                                 MonoInst **args;
8357
8358                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8359                                 for (i = 0; i < n; ++i)
8360                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8361                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8362                                 /*
8363                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8364                                  * have to emit a normal return since llvm expects it.
8365                                  */
8366                                 if (cfg->ret)
8367                                         emit_setret (cfg, ins);
8368                                 MONO_INST_NEW (cfg, ins, OP_BR);
8369                                 ins->inst_target_bb = end_bblock;
8370                                 MONO_ADD_INS (cfg->cbb, ins);
8371                                 link_bblock (cfg, cfg->cbb, end_bblock);
8372                                 ip += 5;
8373                                 break;
8374                         } else if (cfg->backend->have_op_tail_call) {
8375                                 /* Handle tail calls similarly to calls */
8376                                 DISABLE_AOT (cfg);
8377
8378                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8379                                 call->method = cmethod;
8380                                 call->tail_call = TRUE;
8381                                 call->signature = mono_method_signature (cmethod);
8382                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8383                                 call->inst.inst_p0 = cmethod;
8384                                 for (i = 0; i < n; ++i)
8385                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8386
8387                                 if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
8388                                         call->vret_var = cfg->vret_addr;
8389
8390                                 mono_arch_emit_call (cfg, call);
8391                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8392                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8393                         } else {
8394                                 for (i = 0; i < num_args; ++i)
8395                                         /* Prevent arguments from being optimized away */
8396                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8397
8398                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8399                                 ins = (MonoInst*)call;
8400                                 ins->inst_p0 = cmethod;
8401                                 MONO_ADD_INS (cfg->cbb, ins);
8402                         }
8403
8404                         ip += 5;
8405                         start_new_bblock = 1;
8406                         break;
8407                 }
8408                 case CEE_CALLI: {
8409                         MonoInst *addr;
8410                         MonoMethodSignature *fsig;
8411
8412                         CHECK_OPSIZE (5);
8413                         token = read32 (ip + 1);
8414
8415                         ins = NULL;
8416
8417                         //GSHAREDVT_FAILURE (*ip);
8418                         cmethod = NULL;
8419                         CHECK_STACK (1);
8420                         --sp;
8421                         addr = *sp;
8422                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
8423                         CHECK_CFG_ERROR;
8424
8425                         if (method->dynamic && fsig->pinvoke) {
8426                                 MonoInst *args [3];
8427
8428                                 /*
8429                                  * This is a call through a function pointer using a pinvoke
8430                                  * signature. Have to create a wrapper and call that instead.
8431                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8432                                  * instead based on the signature.
8433                                  */
8434                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8435                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8436                                 args [2] = addr;
8437                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8438                         }
8439
8440                         n = fsig->param_count + fsig->hasthis;
8441
8442                         CHECK_STACK (n);
8443
8444                         //g_assert (!virtual_ || fsig->hasthis);
8445
8446                         sp -= n;
8447
8448                         inline_costs += 10 * num_calls++;
8449
8450                         /*
8451                          * Making generic calls out of gsharedvt methods.
8452                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8453                          * patching gshared method addresses into a gsharedvt method.
8454                          */
8455                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8456                                 /*
8457                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8458                                  */
8459                                 MonoInst *callee = addr;
8460
8461                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8462                                         /* Not tested */
8463                                         GSHAREDVT_FAILURE (*ip);
8464
8465                                 if (cfg->llvm_only)
8466                                         // FIXME:
8467                                         GSHAREDVT_FAILURE (*ip);
8468
8469                                 addr = emit_get_rgctx_sig (cfg, context_used,
8470                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8471                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8472                                 goto calli_end;
8473                         }
8474
8475                         /* Prevent inlining of methods with indirect calls */
8476                         INLINE_FAILURE ("indirect call");
8477
8478                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8479                                 MonoJumpInfoType info_type;
8480                                 gpointer info_data;
8481
8482                                 /*
8483                                  * Instead of emitting an indirect call, emit a direct call
8484                                  * with the contents of the aotconst as the patch info.
8485                                  */
8486                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8487                                         info_type = (MonoJumpInfoType)addr->inst_c1;
8488                                         info_data = addr->inst_p0;
8489                                 } else {
8490                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
8491                                         info_data = addr->inst_right->inst_left;
8492                                 }
8493
8494                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
8495                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
8496                                         NULLIFY_INS (addr);
8497                                         goto calli_end;
8498                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8499                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8500                                         NULLIFY_INS (addr);
8501                                         goto calli_end;
8502                                 }
8503                         }
8504                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8505
8506                         calli_end:
8507
8508                         /* End of call, INS should contain the result of the call, if any */
8509
8510                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8511                                 g_assert (ins);
8512                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8513                         }
8514
8515                         CHECK_CFG_EXCEPTION;
8516
8517                         ip += 5;
8518                         ins_flag = 0;
8519                         constrained_class = NULL;
8520                         break;
8521                 }
8522                 case CEE_CALL:
8523                 case CEE_CALLVIRT: {
8524                         MonoInst *addr = NULL;
8525                         MonoMethodSignature *fsig = NULL;
8526                         int array_rank = 0;
8527                         int virtual_ = *ip == CEE_CALLVIRT;
8528                         gboolean pass_imt_from_rgctx = FALSE;
8529                         MonoInst *imt_arg = NULL;
8530                         MonoInst *keep_this_alive = NULL;
8531                         gboolean pass_vtable = FALSE;
8532                         gboolean pass_mrgctx = FALSE;
8533                         MonoInst *vtable_arg = NULL;
8534                         gboolean check_this = FALSE;
8535                         gboolean supported_tail_call = FALSE;
8536                         gboolean tail_call = FALSE;
8537                         gboolean need_seq_point = FALSE;
8538                         guint32 call_opcode = *ip;
8539                         gboolean emit_widen = TRUE;
8540                         gboolean push_res = TRUE;
8541                         gboolean skip_ret = FALSE;
8542                         gboolean delegate_invoke = FALSE;
8543                         gboolean direct_icall = FALSE;
8544                         gboolean constrained_partial_call = FALSE;
8545                         MonoMethod *cil_method;
8546
8547                         CHECK_OPSIZE (5);
8548                         token = read32 (ip + 1);
8549
8550                         ins = NULL;
8551
8552                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8553                         CHECK_CFG_ERROR;
8554
8555                         cil_method = cmethod;
8556                                 
8557                         if (constrained_class) {
8558                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8559                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8560                                                 g_assert (!cmethod->klass->valuetype);
8561                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8562                                                         constrained_partial_call = TRUE;
8563                                         }
8564                                 }
8565
8566                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8567                                         if (cfg->verbose_level > 2)
8568                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8569                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8570                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8571                                                   cfg->gshared)) {
8572                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8573                                                 CHECK_CFG_ERROR;
8574                                         }
8575                                 } else {
8576                                         if (cfg->verbose_level > 2)
8577                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8578
8579                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8580                                                 /* 
8581                                                  * This is needed since get_method_constrained can't find 
8582                                                  * the method in klass representing a type var.
8583                                                  * The type var is guaranteed to be a reference type in this
8584                                                  * case.
8585                                                  */
8586                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8587                                                         g_assert (!cmethod->klass->valuetype);
8588                                         } else {
8589                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8590                                                 CHECK_CFG_ERROR;
8591                                         }
8592                                 }
8593
8594                                 if (constrained_class->enumtype && !strcmp (cmethod->name, "GetHashCode")) {
8595                                         /* Use the corresponding method from the base type to avoid boxing */
8596                                         MonoType *base_type = mono_class_enum_basetype (constrained_class);
8597                                         g_assert (base_type);
8598                                         constrained_class = mono_class_from_mono_type (base_type);
8599                                         cmethod = mono_class_get_method_from_name (constrained_class, cmethod->name, 0);
8600                                         g_assert (cmethod);
8601                                 }
8602                         }
8603                                         
8604                         if (!dont_verify && !cfg->skip_visibility) {
8605                                 MonoMethod *target_method = cil_method;
8606                                 if (method->is_inflated) {
8607                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
8608                                         CHECK_CFG_ERROR;
8609                                 }
8610                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8611                                         !mono_method_can_access_method (method, cil_method))
8612                                         emit_method_access_failure (cfg, method, cil_method);
8613                         }
8614
8615                         if (mono_security_core_clr_enabled ())
8616                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8617
8618                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8619                                 /* MS.NET seems to silently convert this to a callvirt */
8620                                 virtual_ = 1;
8621
8622                         {
8623                                 /*
8624                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8625                                  * converts to a callvirt.
8626                                  *
8627                                  * tests/bug-515884.il is an example of this behavior
8628                                  */
8629                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8630                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8631                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8632                                         virtual_ = 1;
8633                         }
8634
8635                         if (!cmethod->klass->inited)
8636                                 if (!mono_class_init (cmethod->klass))
8637                                         TYPE_LOAD_ERROR (cmethod->klass);
8638
8639                         fsig = mono_method_signature (cmethod);
8640                         if (!fsig)
8641                                 LOAD_ERROR;
8642                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8643                                 mini_class_is_system_array (cmethod->klass)) {
8644                                 array_rank = cmethod->klass->rank;
8645                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8646                                 direct_icall = TRUE;
8647                         } else if (fsig->pinvoke) {
8648                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8649                                 fsig = mono_method_signature (wrapper);
8650                         } else if (constrained_class) {
8651                         } else {
8652                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8653                                 CHECK_CFG_ERROR;
8654                         }
8655
8656                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
8657                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
8658
8659                         /* See code below */
8660                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8661                                 MonoBasicBlock *tbb;
8662
8663                                 GET_BBLOCK (cfg, tbb, ip + 5);
8664                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8665                                         /*
8666                                          * We want to extend the try block to cover the call, but we can't do it if the
8667                                          * call is made directly since its followed by an exception check.
8668                                          */
8669                                         direct_icall = FALSE;
8670                                 }
8671                         }
8672
8673                         mono_save_token_info (cfg, image, token, cil_method);
8674
8675                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8676                                 need_seq_point = TRUE;
8677
8678                         /* Don't support calls made using type arguments for now */
8679                         /*
8680                           if (cfg->gsharedvt) {
8681                           if (mini_is_gsharedvt_signature (fsig))
8682                           GSHAREDVT_FAILURE (*ip);
8683                           }
8684                         */
8685
8686                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8687                                 g_assert_not_reached ();
8688
8689                         n = fsig->param_count + fsig->hasthis;
8690
8691                         if (!cfg->gshared && mono_class_is_gtd (cmethod->klass))
8692                                 UNVERIFIED;
8693
8694                         if (!cfg->gshared)
8695                                 g_assert (!mono_method_check_context_used (cmethod));
8696
8697                         CHECK_STACK (n);
8698
8699                         //g_assert (!virtual_ || fsig->hasthis);
8700
8701                         sp -= n;
8702
8703                         /*
8704                          * We have the `constrained.' prefix opcode.
8705                          */
8706                         if (constrained_class) {
8707                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8708                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8709                                                 /* The 'Own method' case below */
8710                                         } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) {
8711                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8712                                         } else {
8713                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8714                                                 CHECK_CFG_EXCEPTION;
8715                                                 g_assert (ins);
8716                                                 goto call_end;
8717                                         }
8718                                 }
8719
8720                                 if (constrained_partial_call) {
8721                                         gboolean need_box = TRUE;
8722
8723                                         /*
8724                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8725                                          * called method is not known at compile time either. The called method could end up being
8726                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8727                                          * to box the receiver.
8728                                          * A simple solution would be to box always and make a normal virtual call, but that would
8729                                          * be bad performance wise.
8730                                          */
8731                                         if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) {
8732                                                 /*
8733                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8734                                                  */
8735                                                 need_box = FALSE;
8736                                         }
8737
8738                                         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)) {
8739                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8740                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8741                                                 ins->klass = constrained_class;
8742                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8743                                                 CHECK_CFG_EXCEPTION;
8744                                         } else if (need_box) {
8745                                                 MonoInst *box_type;
8746                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8747                                                 MonoInst *nonbox_call;
8748
8749                                                 /*
8750                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8751                                                  * if needed.
8752                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8753                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8754                                                  */
8755                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8756
8757                                                 NEW_BBLOCK (cfg, is_ref_bb);
8758                                                 NEW_BBLOCK (cfg, end_bb);
8759
8760                                                 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);
8761                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
8762                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
8763
8764                                                 /* Non-ref case */
8765                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8766
8767                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8768
8769                                                 /* Ref case */
8770                                                 MONO_START_BB (cfg, is_ref_bb);
8771                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8772                                                 ins->klass = constrained_class;
8773                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8774                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8775
8776                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8777
8778                                                 MONO_START_BB (cfg, end_bb);
8779                                                 cfg->cbb = end_bb;
8780
8781                                                 nonbox_call->dreg = ins->dreg;
8782                                                 goto call_end;
8783                                         } else {
8784                                                 g_assert (mono_class_is_interface (cmethod->klass));
8785                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8786                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8787                                                 goto call_end;
8788                                         }
8789                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8790                                         /*
8791                                          * The type parameter is instantiated as a valuetype,
8792                                          * but that type doesn't override the method we're
8793                                          * calling, so we need to box `this'.
8794                                          */
8795                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8796                                         ins->klass = constrained_class;
8797                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8798                                         CHECK_CFG_EXCEPTION;
8799                                 } else if (!constrained_class->valuetype) {
8800                                         int dreg = alloc_ireg_ref (cfg);
8801
8802                                         /*
8803                                          * The type parameter is instantiated as a reference
8804                                          * type.  We have a managed pointer on the stack, so
8805                                          * we need to dereference it here.
8806                                          */
8807                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8808                                         ins->type = STACK_OBJ;
8809                                         sp [0] = ins;
8810                                 } else {
8811                                         if (cmethod->klass->valuetype) {
8812                                                 /* Own method */
8813                                         } else {
8814                                                 /* Interface method */
8815                                                 int ioffset, slot;
8816
8817                                                 mono_class_setup_vtable (constrained_class);
8818                                                 CHECK_TYPELOAD (constrained_class);
8819                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8820                                                 if (ioffset == -1)
8821                                                         TYPE_LOAD_ERROR (constrained_class);
8822                                                 slot = mono_method_get_vtable_slot (cmethod);
8823                                                 if (slot == -1)
8824                                                         TYPE_LOAD_ERROR (cmethod->klass);
8825                                                 cmethod = constrained_class->vtable [ioffset + slot];
8826
8827                                                 if (cmethod->klass == mono_defaults.enum_class) {
8828                                                         /* Enum implements some interfaces, so treat this as the first case */
8829                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8830                                                         ins->klass = constrained_class;
8831                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8832                                                         CHECK_CFG_EXCEPTION;
8833                                                 }
8834                                         }
8835                                         virtual_ = 0;
8836                                 }
8837                                 constrained_class = NULL;
8838                         }
8839
8840                         if (check_call_signature (cfg, fsig, sp))
8841                                 UNVERIFIED;
8842
8843                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8844                                 delegate_invoke = TRUE;
8845
8846                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8847                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8848                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8849                                         emit_widen = FALSE;
8850                                 }
8851
8852                                 goto call_end;
8853                         }
8854
8855                         /* 
8856                          * If the callee is a shared method, then its static cctor
8857                          * might not get called after the call was patched.
8858                          */
8859                         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)) {
8860                                 emit_class_init (cfg, cmethod->klass);
8861                                 CHECK_TYPELOAD (cmethod->klass);
8862                         }
8863
8864                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8865
8866                         if (cfg->gshared) {
8867                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8868
8869                                 context_used = mini_method_check_context_used (cfg, cmethod);
8870
8871                                 if (context_used && mono_class_is_interface (cmethod->klass)) {
8872                                         /* Generic method interface
8873                                            calls are resolved via a
8874                                            helper function and don't
8875                                            need an imt. */
8876                                         if (!cmethod_context || !cmethod_context->method_inst)
8877                                                 pass_imt_from_rgctx = TRUE;
8878                                 }
8879
8880                                 /*
8881                                  * If a shared method calls another
8882                                  * shared method then the caller must
8883                                  * have a generic sharing context
8884                                  * because the magic trampoline
8885                                  * requires it.  FIXME: We shouldn't
8886                                  * have to force the vtable/mrgctx
8887                                  * variable here.  Instead there
8888                                  * should be a flag in the cfg to
8889                                  * request a generic sharing context.
8890                                  */
8891                                 if (context_used &&
8892                                                 ((cfg->method->flags & METHOD_ATTRIBUTE_STATIC) || cfg->method->klass->valuetype))
8893                                         mono_get_vtable_var (cfg);
8894                         }
8895
8896                         if (pass_vtable) {
8897                                 if (context_used) {
8898                                         vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8899                                 } else {
8900                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8901
8902                                         CHECK_TYPELOAD (cmethod->klass);
8903                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8904                                 }
8905                         }
8906
8907                         if (pass_mrgctx) {
8908                                 g_assert (!vtable_arg);
8909
8910                                 if (!cfg->compile_aot) {
8911                                         /* 
8912                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8913                                          * for type load errors before.
8914                                          */
8915                                         mono_class_setup_vtable (cmethod->klass);
8916                                         CHECK_TYPELOAD (cmethod->klass);
8917                                 }
8918
8919                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8920
8921                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8922                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8923                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8924                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8925                                         if (virtual_)
8926                                                 check_this = TRUE;
8927                                         virtual_ = 0;
8928                                 }
8929                         }
8930
8931                         if (pass_imt_from_rgctx) {
8932                                 g_assert (!pass_vtable);
8933
8934                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8935                                         cmethod, MONO_RGCTX_INFO_METHOD);
8936                         }
8937
8938                         if (check_this)
8939                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8940
8941                         /* Calling virtual generic methods */
8942                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
8943                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8944                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8945                             fsig->generic_param_count && 
8946                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
8947                                 !cfg->llvm_only) {
8948                                 MonoInst *this_temp, *this_arg_temp, *store;
8949                                 MonoInst *iargs [4];
8950
8951                                 g_assert (fsig->is_inflated);
8952
8953                                 /* Prevent inlining of methods that contain indirect calls */
8954                                 INLINE_FAILURE ("virtual generic call");
8955
8956                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8957                                         GSHAREDVT_FAILURE (*ip);
8958
8959                                 if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
8960                                         g_assert (!imt_arg);
8961                                         if (!context_used)
8962                                                 g_assert (cmethod->is_inflated);
8963                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8964                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8965                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8966                                 } else {
8967                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8968                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8969                                         MONO_ADD_INS (cfg->cbb, store);
8970
8971                                         /* FIXME: This should be a managed pointer */
8972                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8973
8974                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8975                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8976                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8977                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8978                                         addr = mono_emit_jit_icall (cfg,
8979                                                                                                 mono_helper_compile_generic_method, iargs);
8980
8981                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8982
8983                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8984                                 }
8985
8986                                 goto call_end;
8987                         }
8988
8989                         /*
8990                          * Implement a workaround for the inherent races involved in locking:
8991                          * Monitor.Enter ()
8992                          * try {
8993                          * } finally {
8994                          *    Monitor.Exit ()
8995                          * }
8996                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8997                          * try block, the Exit () won't be executed, see:
8998                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8999                          * To work around this, we extend such try blocks to include the last x bytes
9000                          * of the Monitor.Enter () call.
9001                          */
9002                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9003                                 MonoBasicBlock *tbb;
9004
9005                                 GET_BBLOCK (cfg, tbb, ip + 5);
9006                                 /* 
9007                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9008                                  * from Monitor.Enter like ArgumentNullException.
9009                                  */
9010                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9011                                         /* Mark this bblock as needing to be extended */
9012                                         tbb->extend_try_block = TRUE;
9013                                 }
9014                         }
9015
9016                         /* Conversion to a JIT intrinsic */
9017                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9018                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9019                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9020                                         emit_widen = FALSE;
9021                                 }
9022                                 goto call_end;
9023                         }
9024                         CHECK_CFG_ERROR;
9025                         
9026                         /* Inlining */
9027                         if ((cfg->opt & MONO_OPT_INLINE) &&
9028                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9029                             mono_method_check_inlining (cfg, cmethod)) {
9030                                 int costs;
9031                                 gboolean always = FALSE;
9032
9033                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9034                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9035                                         /* Prevent inlining of methods that call wrappers */
9036                                         INLINE_FAILURE ("wrapper call");
9037                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9038                                         always = TRUE;
9039                                 }
9040
9041                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9042                                 if (costs) {
9043                                         cfg->real_offset += 5;
9044
9045                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9046                                                 /* *sp is already set by inline_method */
9047                                                 sp++;
9048                                                 push_res = FALSE;
9049                                         }
9050
9051                                         inline_costs += costs;
9052
9053                                         goto call_end;
9054                                 }
9055                         }
9056
9057                         /* Tail recursion elimination */
9058                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9059                                 gboolean has_vtargs = FALSE;
9060                                 int i;
9061
9062                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9063                                 INLINE_FAILURE ("tail call");
9064
9065                                 /* keep it simple */
9066                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9067                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9068                                                 has_vtargs = TRUE;
9069                                 }
9070
9071                                 if (!has_vtargs) {
9072                                         if (need_seq_point) {
9073                                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9074                                                 need_seq_point = FALSE;
9075                                         }
9076                                         for (i = 0; i < n; ++i)
9077                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9078                                         MONO_INST_NEW (cfg, ins, OP_BR);
9079                                         MONO_ADD_INS (cfg->cbb, ins);
9080                                         tblock = start_bblock->out_bb [0];
9081                                         link_bblock (cfg, cfg->cbb, tblock);
9082                                         ins->inst_target_bb = tblock;
9083                                         start_new_bblock = 1;
9084
9085                                         /* skip the CEE_RET, too */
9086                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9087                                                 skip_ret = TRUE;
9088                                         push_res = FALSE;
9089                                         goto call_end;
9090                                 }
9091                         }
9092
9093                         inline_costs += 10 * num_calls++;
9094
9095                         /*
9096                          * Synchronized wrappers.
9097                          * Its hard to determine where to replace a method with its synchronized
9098                          * wrapper without causing an infinite recursion. The current solution is
9099                          * to add the synchronized wrapper in the trampolines, and to
9100                          * change the called method to a dummy wrapper, and resolve that wrapper
9101                          * to the real method in mono_jit_compile_method ().
9102                          */
9103                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9104                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9105                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9106                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9107                         }
9108
9109                         /*
9110                          * Making generic calls out of gsharedvt methods.
9111                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9112                          * patching gshared method addresses into a gsharedvt method.
9113                          */
9114                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) &&
9115                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9116                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9117                                 MonoRgctxInfoType info_type;
9118
9119                                 if (virtual_) {
9120                                         //if (mono_class_is_interface (cmethod->klass))
9121                                                 //GSHAREDVT_FAILURE (*ip);
9122                                         // disable for possible remoting calls
9123                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9124                                                 GSHAREDVT_FAILURE (*ip);
9125                                         if (fsig->generic_param_count) {
9126                                                 /* virtual generic call */
9127                                                 g_assert (!imt_arg);
9128                                                 /* Same as the virtual generic case above */
9129                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9130                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9131                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9132                                                 vtable_arg = NULL;
9133                                         } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) {
9134                                                 /* This can happen when we call a fully instantiated iface method */
9135                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9136                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9137                                                 vtable_arg = NULL;
9138                                         }
9139                                 }
9140
9141                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9142                                         keep_this_alive = sp [0];
9143
9144                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9145                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9146                                 else
9147                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9148                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9149
9150                                 if (cfg->llvm_only) {
9151                                         // FIXME: Avoid initializing vtable_arg
9152                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9153                                 } else {
9154                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9155                                 }
9156                                 goto call_end;
9157                         }
9158
9159                         /* Generic sharing */
9160
9161                         /*
9162                          * Use this if the callee is gsharedvt sharable too, since
9163                          * at runtime we might find an instantiation so the call cannot
9164                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9165                          */
9166                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9167                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9168                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9169                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9170                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9171                                 INLINE_FAILURE ("gshared");
9172
9173                                 g_assert (cfg->gshared && cmethod);
9174                                 g_assert (!addr);
9175
9176                                 /*
9177                                  * We are compiling a call to a
9178                                  * generic method from shared code,
9179                                  * which means that we have to look up
9180                                  * the method in the rgctx and do an
9181                                  * indirect call.
9182                                  */
9183                                 if (fsig->hasthis)
9184                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9185
9186                                 if (cfg->llvm_only) {
9187                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9188                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9189                                         else
9190                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9191                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9192                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9193                                 } else {
9194                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9195                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9196                                 }
9197                                 goto call_end;
9198                         }
9199
9200                         /* Direct calls to icalls */
9201                         if (direct_icall) {
9202                                 MonoMethod *wrapper;
9203                                 int costs;
9204
9205                                 /* Inline the wrapper */
9206                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9207
9208                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9209                                 g_assert (costs > 0);
9210                                 cfg->real_offset += 5;
9211
9212                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9213                                         /* *sp is already set by inline_method */
9214                                         sp++;
9215                                         push_res = FALSE;
9216                                 }
9217
9218                                 inline_costs += costs;
9219
9220                                 goto call_end;
9221                         }
9222                                         
9223                         /* Array methods */
9224                         if (array_rank) {
9225                                 MonoInst *addr;
9226
9227                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9228                                         MonoInst *val = sp [fsig->param_count];
9229
9230                                         if (val->type == STACK_OBJ) {
9231                                                 MonoInst *iargs [2];
9232
9233                                                 iargs [0] = sp [0];
9234                                                 iargs [1] = val;
9235                                                 
9236                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9237                                         }
9238                                         
9239                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9240                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9241                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
9242                                                 emit_write_barrier (cfg, addr, val);
9243                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9244                                                 GSHAREDVT_FAILURE (*ip);
9245                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9246                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9247
9248                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9249                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9250                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9251                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9252                                         CHECK_TYPELOAD (cmethod->klass);
9253                                         
9254                                         readonly = FALSE;
9255                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9256                                         ins = addr;
9257                                 } else {
9258                                         g_assert_not_reached ();
9259                                 }
9260
9261                                 emit_widen = FALSE;
9262                                 goto call_end;
9263                         }
9264
9265                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9266                         if (ins)
9267                                 goto call_end;
9268
9269                         /* Tail prefix / tail call optimization */
9270
9271                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9272                         /* FIXME: runtime generic context pointer for jumps? */
9273                         /* FIXME: handle this for generic sharing eventually */
9274                         if ((ins_flag & MONO_INST_TAILCALL) &&
9275                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9276                                 supported_tail_call = TRUE;
9277
9278                         if (supported_tail_call) {
9279                                 MonoCallInst *call;
9280
9281                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9282                                 INLINE_FAILURE ("tail call");
9283
9284                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9285
9286                                 if (cfg->backend->have_op_tail_call) {
9287                                         /* Handle tail calls similarly to normal calls */
9288                                         tail_call = TRUE;
9289                                 } else {
9290                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9291
9292                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9293                                         call->tail_call = TRUE;
9294                                         call->method = cmethod;
9295                                         call->signature = mono_method_signature (cmethod);
9296
9297                                         /*
9298                                          * We implement tail calls by storing the actual arguments into the 
9299                                          * argument variables, then emitting a CEE_JMP.
9300                                          */
9301                                         for (i = 0; i < n; ++i) {
9302                                                 /* Prevent argument from being register allocated */
9303                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9304                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9305                                         }
9306                                         ins = (MonoInst*)call;
9307                                         ins->inst_p0 = cmethod;
9308                                         ins->inst_p1 = arg_array [0];
9309                                         MONO_ADD_INS (cfg->cbb, ins);
9310                                         link_bblock (cfg, cfg->cbb, end_bblock);
9311                                         start_new_bblock = 1;
9312
9313                                         // FIXME: Eliminate unreachable epilogs
9314
9315                                         /*
9316                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9317                                          * only reachable from this call.
9318                                          */
9319                                         GET_BBLOCK (cfg, tblock, ip + 5);
9320                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9321                                                 skip_ret = TRUE;
9322                                         push_res = FALSE;
9323
9324                                         goto call_end;
9325                                 }
9326                         }
9327
9328                         /*
9329                          * Virtual calls in llvm-only mode.
9330                          */
9331                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9332                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9333                                 goto call_end;
9334                         }
9335
9336                         /* Common call */
9337                         if (!(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
9338                                 INLINE_FAILURE ("call");
9339                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9340                                                                                           imt_arg, vtable_arg);
9341
9342                         if (tail_call && !cfg->llvm_only) {
9343                                 link_bblock (cfg, cfg->cbb, end_bblock);
9344                                 start_new_bblock = 1;
9345
9346                                 // FIXME: Eliminate unreachable epilogs
9347
9348                                 /*
9349                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9350                                  * only reachable from this call.
9351                                  */
9352                                 GET_BBLOCK (cfg, tblock, ip + 5);
9353                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9354                                         skip_ret = TRUE;
9355                                 push_res = FALSE;
9356                         }
9357
9358                         call_end:
9359
9360                         /* End of call, INS should contain the result of the call, if any */
9361
9362                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9363                                 g_assert (ins);
9364                                 if (emit_widen)
9365                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9366                                 else
9367                                         *sp++ = ins;
9368                         }
9369
9370                         if (keep_this_alive) {
9371                                 MonoInst *dummy_use;
9372
9373                                 /* See mono_emit_method_call_full () */
9374                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9375                         }
9376
9377                         if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
9378                                 /*
9379                                  * Clang can convert these calls to tail calls which screw up the stack
9380                                  * walk. This happens even when the -fno-optimize-sibling-calls
9381                                  * option is passed to clang.
9382                                  * Work around this by emitting a dummy call.
9383                                  */
9384                                 mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
9385                         }
9386
9387                         CHECK_CFG_EXCEPTION;
9388
9389                         ip += 5;
9390                         if (skip_ret) {
9391                                 g_assert (*ip == CEE_RET);
9392                                 ip += 1;
9393                         }
9394                         ins_flag = 0;
9395                         constrained_class = NULL;
9396                         if (need_seq_point)
9397                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9398                         break;
9399                 }
9400                 case CEE_RET:
9401                         if (cfg->method != method) {
9402                                 /* return from inlined method */
9403                                 /* 
9404                                  * If in_count == 0, that means the ret is unreachable due to
9405                                  * being preceeded by a throw. In that case, inline_method () will
9406                                  * handle setting the return value 
9407                                  * (test case: test_0_inline_throw ()).
9408                                  */
9409                                 if (return_var && cfg->cbb->in_count) {
9410                                         MonoType *ret_type = mono_method_signature (method)->ret;
9411
9412                                         MonoInst *store;
9413                                         CHECK_STACK (1);
9414                                         --sp;
9415
9416                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9417                                                 UNVERIFIED;
9418
9419                                         //g_assert (returnvar != -1);
9420                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9421                                         cfg->ret_var_set = TRUE;
9422                                 } 
9423                         } else {
9424                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9425
9426                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9427                                         emit_pop_lmf (cfg);
9428
9429                                 if (cfg->ret) {
9430                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9431
9432                                         if (seq_points && !sym_seq_points) {
9433                                                 /* 
9434                                                  * Place a seq point here too even through the IL stack is not
9435                                                  * empty, so a step over on
9436                                                  * call <FOO>
9437                                                  * ret
9438                                                  * will work correctly.
9439                                                  */
9440                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9441                                                 MONO_ADD_INS (cfg->cbb, ins);
9442                                         }
9443
9444                                         g_assert (!return_var);
9445                                         CHECK_STACK (1);
9446                                         --sp;
9447
9448                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9449                                                 UNVERIFIED;
9450
9451                                         emit_setret (cfg, *sp);
9452                                 }
9453                         }
9454                         if (sp != stack_start)
9455                                 UNVERIFIED;
9456                         MONO_INST_NEW (cfg, ins, OP_BR);
9457                         ip++;
9458                         ins->inst_target_bb = end_bblock;
9459                         MONO_ADD_INS (cfg->cbb, ins);
9460                         link_bblock (cfg, cfg->cbb, end_bblock);
9461                         start_new_bblock = 1;
9462                         break;
9463                 case CEE_BR_S:
9464                         CHECK_OPSIZE (2);
9465                         MONO_INST_NEW (cfg, ins, OP_BR);
9466                         ip++;
9467                         target = ip + 1 + (signed char)(*ip);
9468                         ++ip;
9469                         GET_BBLOCK (cfg, tblock, target);
9470                         link_bblock (cfg, cfg->cbb, tblock);
9471                         ins->inst_target_bb = tblock;
9472                         if (sp != stack_start) {
9473                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9474                                 sp = stack_start;
9475                                 CHECK_UNVERIFIABLE (cfg);
9476                         }
9477                         MONO_ADD_INS (cfg->cbb, ins);
9478                         start_new_bblock = 1;
9479                         inline_costs += BRANCH_COST;
9480                         break;
9481                 case CEE_BEQ_S:
9482                 case CEE_BGE_S:
9483                 case CEE_BGT_S:
9484                 case CEE_BLE_S:
9485                 case CEE_BLT_S:
9486                 case CEE_BNE_UN_S:
9487                 case CEE_BGE_UN_S:
9488                 case CEE_BGT_UN_S:
9489                 case CEE_BLE_UN_S:
9490                 case CEE_BLT_UN_S:
9491                         CHECK_OPSIZE (2);
9492                         CHECK_STACK (2);
9493                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9494                         ip++;
9495                         target = ip + 1 + *(signed char*)ip;
9496                         ip++;
9497
9498                         ADD_BINCOND (NULL);
9499
9500                         sp = stack_start;
9501                         inline_costs += BRANCH_COST;
9502                         break;
9503                 case CEE_BR:
9504                         CHECK_OPSIZE (5);
9505                         MONO_INST_NEW (cfg, ins, OP_BR);
9506                         ip++;
9507
9508                         target = ip + 4 + (gint32)read32(ip);
9509                         ip += 4;
9510                         GET_BBLOCK (cfg, tblock, target);
9511                         link_bblock (cfg, cfg->cbb, tblock);
9512                         ins->inst_target_bb = tblock;
9513                         if (sp != stack_start) {
9514                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9515                                 sp = stack_start;
9516                                 CHECK_UNVERIFIABLE (cfg);
9517                         }
9518
9519                         MONO_ADD_INS (cfg->cbb, ins);
9520
9521                         start_new_bblock = 1;
9522                         inline_costs += BRANCH_COST;
9523                         break;
9524                 case CEE_BRFALSE_S:
9525                 case CEE_BRTRUE_S:
9526                 case CEE_BRFALSE:
9527                 case CEE_BRTRUE: {
9528                         MonoInst *cmp;
9529                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9530                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9531                         guint32 opsize = is_short ? 1 : 4;
9532
9533                         CHECK_OPSIZE (opsize);
9534                         CHECK_STACK (1);
9535                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9536                                 UNVERIFIED;
9537                         ip ++;
9538                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9539                         ip += opsize;
9540
9541                         sp--;
9542
9543                         GET_BBLOCK (cfg, tblock, target);
9544                         link_bblock (cfg, cfg->cbb, tblock);
9545                         GET_BBLOCK (cfg, tblock, ip);
9546                         link_bblock (cfg, cfg->cbb, tblock);
9547
9548                         if (sp != stack_start) {
9549                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9550                                 CHECK_UNVERIFIABLE (cfg);
9551                         }
9552
9553                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9554                         cmp->sreg1 = sp [0]->dreg;
9555                         type_from_op (cfg, cmp, sp [0], NULL);
9556                         CHECK_TYPE (cmp);
9557
9558 #if SIZEOF_REGISTER == 4
9559                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9560                                 /* Convert it to OP_LCOMPARE */
9561                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9562                                 ins->type = STACK_I8;
9563                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9564                                 ins->inst_l = 0;
9565                                 MONO_ADD_INS (cfg->cbb, ins);
9566                                 cmp->opcode = OP_LCOMPARE;
9567                                 cmp->sreg2 = ins->dreg;
9568                         }
9569 #endif
9570                         MONO_ADD_INS (cfg->cbb, cmp);
9571
9572                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9573                         type_from_op (cfg, ins, sp [0], NULL);
9574                         MONO_ADD_INS (cfg->cbb, ins);
9575                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9576                         GET_BBLOCK (cfg, tblock, target);
9577                         ins->inst_true_bb = tblock;
9578                         GET_BBLOCK (cfg, tblock, ip);
9579                         ins->inst_false_bb = tblock;
9580                         start_new_bblock = 2;
9581
9582                         sp = stack_start;
9583                         inline_costs += BRANCH_COST;
9584                         break;
9585                 }
9586                 case CEE_BEQ:
9587                 case CEE_BGE:
9588                 case CEE_BGT:
9589                 case CEE_BLE:
9590                 case CEE_BLT:
9591                 case CEE_BNE_UN:
9592                 case CEE_BGE_UN:
9593                 case CEE_BGT_UN:
9594                 case CEE_BLE_UN:
9595                 case CEE_BLT_UN:
9596                         CHECK_OPSIZE (5);
9597                         CHECK_STACK (2);
9598                         MONO_INST_NEW (cfg, ins, *ip);
9599                         ip++;
9600                         target = ip + 4 + (gint32)read32(ip);
9601                         ip += 4;
9602
9603                         ADD_BINCOND (NULL);
9604
9605                         sp = stack_start;
9606                         inline_costs += BRANCH_COST;
9607                         break;
9608                 case CEE_SWITCH: {
9609                         MonoInst *src1;
9610                         MonoBasicBlock **targets;
9611                         MonoBasicBlock *default_bblock;
9612                         MonoJumpInfoBBTable *table;
9613                         int offset_reg = alloc_preg (cfg);
9614                         int target_reg = alloc_preg (cfg);
9615                         int table_reg = alloc_preg (cfg);
9616                         int sum_reg = alloc_preg (cfg);
9617                         gboolean use_op_switch;
9618
9619                         CHECK_OPSIZE (5);
9620                         CHECK_STACK (1);
9621                         n = read32 (ip + 1);
9622                         --sp;
9623                         src1 = sp [0];
9624                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9625                                 UNVERIFIED;
9626
9627                         ip += 5;
9628                         CHECK_OPSIZE (n * sizeof (guint32));
9629                         target = ip + n * sizeof (guint32);
9630
9631                         GET_BBLOCK (cfg, default_bblock, target);
9632                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9633
9634                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9635                         for (i = 0; i < n; ++i) {
9636                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9637                                 targets [i] = tblock;
9638                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9639                                 ip += 4;
9640                         }
9641
9642                         if (sp != stack_start) {
9643                                 /* 
9644                                  * Link the current bb with the targets as well, so handle_stack_args
9645                                  * will set their in_stack correctly.
9646                                  */
9647                                 link_bblock (cfg, cfg->cbb, default_bblock);
9648                                 for (i = 0; i < n; ++i)
9649                                         link_bblock (cfg, cfg->cbb, targets [i]);
9650
9651                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9652                                 sp = stack_start;
9653                                 CHECK_UNVERIFIABLE (cfg);
9654
9655                                 /* Undo the links */
9656                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9657                                 for (i = 0; i < n; ++i)
9658                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9659                         }
9660
9661                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9662                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9663
9664                         for (i = 0; i < n; ++i)
9665                                 link_bblock (cfg, cfg->cbb, targets [i]);
9666
9667                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9668                         table->table = targets;
9669                         table->table_size = n;
9670
9671                         use_op_switch = FALSE;
9672 #ifdef TARGET_ARM
9673                         /* ARM implements SWITCH statements differently */
9674                         /* FIXME: Make it use the generic implementation */
9675                         if (!cfg->compile_aot)
9676                                 use_op_switch = TRUE;
9677 #endif
9678
9679                         if (COMPILE_LLVM (cfg))
9680                                 use_op_switch = TRUE;
9681
9682                         cfg->cbb->has_jump_table = 1;
9683
9684                         if (use_op_switch) {
9685                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9686                                 ins->sreg1 = src1->dreg;
9687                                 ins->inst_p0 = table;
9688                                 ins->inst_many_bb = targets;
9689                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
9690                                 MONO_ADD_INS (cfg->cbb, ins);
9691                         } else {
9692                                 if (sizeof (gpointer) == 8)
9693                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9694                                 else
9695                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9696
9697 #if SIZEOF_REGISTER == 8
9698                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9699                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9700 #endif
9701
9702                                 if (cfg->compile_aot) {
9703                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9704                                 } else {
9705                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9706                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9707                                         ins->inst_p0 = table;
9708                                         ins->dreg = table_reg;
9709                                         MONO_ADD_INS (cfg->cbb, ins);
9710                                 }
9711
9712                                 /* FIXME: Use load_memindex */
9713                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9714                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9715                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9716                         }
9717                         start_new_bblock = 1;
9718                         inline_costs += (BRANCH_COST * 2);
9719                         break;
9720                 }
9721                 case CEE_LDIND_I1:
9722                 case CEE_LDIND_U1:
9723                 case CEE_LDIND_I2:
9724                 case CEE_LDIND_U2:
9725                 case CEE_LDIND_I4:
9726                 case CEE_LDIND_U4:
9727                 case CEE_LDIND_I8:
9728                 case CEE_LDIND_I:
9729                 case CEE_LDIND_R4:
9730                 case CEE_LDIND_R8:
9731                 case CEE_LDIND_REF:
9732                         CHECK_STACK (1);
9733                         --sp;
9734
9735                         switch (*ip) {
9736                         case CEE_LDIND_R4:
9737                         case CEE_LDIND_R8:
9738                                 dreg = alloc_freg (cfg);
9739                                 break;
9740                         case CEE_LDIND_I8:
9741                                 dreg = alloc_lreg (cfg);
9742                                 break;
9743                         case CEE_LDIND_REF:
9744                                 dreg = alloc_ireg_ref (cfg);
9745                                 break;
9746                         default:
9747                                 dreg = alloc_preg (cfg);
9748                         }
9749
9750                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9751                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9752                         if (*ip == CEE_LDIND_R4)
9753                                 ins->type = cfg->r4_stack_type;
9754                         ins->flags |= ins_flag;
9755                         MONO_ADD_INS (cfg->cbb, ins);
9756                         *sp++ = ins;
9757                         if (ins_flag & MONO_INST_VOLATILE) {
9758                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9759                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9760                         }
9761                         ins_flag = 0;
9762                         ++ip;
9763                         break;
9764                 case CEE_STIND_REF:
9765                 case CEE_STIND_I1:
9766                 case CEE_STIND_I2:
9767                 case CEE_STIND_I4:
9768                 case CEE_STIND_I8:
9769                 case CEE_STIND_R4:
9770                 case CEE_STIND_R8:
9771                 case CEE_STIND_I:
9772                         CHECK_STACK (2);
9773                         sp -= 2;
9774
9775                         if (ins_flag & MONO_INST_VOLATILE) {
9776                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9777                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9778                         }
9779
9780                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9781                         ins->flags |= ins_flag;
9782                         ins_flag = 0;
9783
9784                         MONO_ADD_INS (cfg->cbb, ins);
9785
9786                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
9787                                 emit_write_barrier (cfg, sp [0], sp [1]);
9788
9789                         inline_costs += 1;
9790                         ++ip;
9791                         break;
9792
9793                 case CEE_MUL:
9794                         CHECK_STACK (2);
9795
9796                         MONO_INST_NEW (cfg, ins, (*ip));
9797                         sp -= 2;
9798                         ins->sreg1 = sp [0]->dreg;
9799                         ins->sreg2 = sp [1]->dreg;
9800                         type_from_op (cfg, ins, sp [0], sp [1]);
9801                         CHECK_TYPE (ins);
9802                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9803
9804                         /* Use the immediate opcodes if possible */
9805                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9806                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9807                                 if (imm_opcode != -1) {
9808                                         ins->opcode = imm_opcode;
9809                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9810                                         ins->sreg2 = -1;
9811
9812                                         NULLIFY_INS (sp [1]);
9813                                 }
9814                         }
9815
9816                         MONO_ADD_INS ((cfg)->cbb, (ins));
9817
9818                         *sp++ = mono_decompose_opcode (cfg, ins);
9819                         ip++;
9820                         break;
9821                 case CEE_ADD:
9822                 case CEE_SUB:
9823                 case CEE_DIV:
9824                 case CEE_DIV_UN:
9825                 case CEE_REM:
9826                 case CEE_REM_UN:
9827                 case CEE_AND:
9828                 case CEE_OR:
9829                 case CEE_XOR:
9830                 case CEE_SHL:
9831                 case CEE_SHR:
9832                 case CEE_SHR_UN:
9833                         CHECK_STACK (2);
9834
9835                         MONO_INST_NEW (cfg, ins, (*ip));
9836                         sp -= 2;
9837                         ins->sreg1 = sp [0]->dreg;
9838                         ins->sreg2 = sp [1]->dreg;
9839                         type_from_op (cfg, ins, sp [0], sp [1]);
9840                         CHECK_TYPE (ins);
9841                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9842                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9843
9844                         /* FIXME: Pass opcode to is_inst_imm */
9845
9846                         /* Use the immediate opcodes if possible */
9847                         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)) {
9848                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9849                                 if (imm_opcode != -1) {
9850                                         ins->opcode = imm_opcode;
9851                                         if (sp [1]->opcode == OP_I8CONST) {
9852 #if SIZEOF_REGISTER == 8
9853                                                 ins->inst_imm = sp [1]->inst_l;
9854 #else
9855                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9856                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9857 #endif
9858                                         }
9859                                         else
9860                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9861                                         ins->sreg2 = -1;
9862
9863                                         /* Might be followed by an instruction added by add_widen_op */
9864                                         if (sp [1]->next == NULL)
9865                                                 NULLIFY_INS (sp [1]);
9866                                 }
9867                         }
9868                         MONO_ADD_INS ((cfg)->cbb, (ins));
9869
9870                         *sp++ = mono_decompose_opcode (cfg, ins);
9871                         ip++;
9872                         break;
9873                 case CEE_NEG:
9874                 case CEE_NOT:
9875                 case CEE_CONV_I1:
9876                 case CEE_CONV_I2:
9877                 case CEE_CONV_I4:
9878                 case CEE_CONV_R4:
9879                 case CEE_CONV_R8:
9880                 case CEE_CONV_U4:
9881                 case CEE_CONV_I8:
9882                 case CEE_CONV_U8:
9883                 case CEE_CONV_OVF_I8:
9884                 case CEE_CONV_OVF_U8:
9885                 case CEE_CONV_R_UN:
9886                         CHECK_STACK (1);
9887
9888                         /* Special case this earlier so we have long constants in the IR */
9889                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9890                                 int data = sp [-1]->inst_c0;
9891                                 sp [-1]->opcode = OP_I8CONST;
9892                                 sp [-1]->type = STACK_I8;
9893 #if SIZEOF_REGISTER == 8
9894                                 if ((*ip) == CEE_CONV_U8)
9895                                         sp [-1]->inst_c0 = (guint32)data;
9896                                 else
9897                                         sp [-1]->inst_c0 = data;
9898 #else
9899                                 sp [-1]->inst_ls_word = data;
9900                                 if ((*ip) == CEE_CONV_U8)
9901                                         sp [-1]->inst_ms_word = 0;
9902                                 else
9903                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9904 #endif
9905                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9906                         }
9907                         else {
9908                                 ADD_UNOP (*ip);
9909                         }
9910                         ip++;
9911                         break;
9912                 case CEE_CONV_OVF_I4:
9913                 case CEE_CONV_OVF_I1:
9914                 case CEE_CONV_OVF_I2:
9915                 case CEE_CONV_OVF_I:
9916                 case CEE_CONV_OVF_U:
9917                         CHECK_STACK (1);
9918
9919                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9920                                 ADD_UNOP (CEE_CONV_OVF_I8);
9921                                 ADD_UNOP (*ip);
9922                         } else {
9923                                 ADD_UNOP (*ip);
9924                         }
9925                         ip++;
9926                         break;
9927                 case CEE_CONV_OVF_U1:
9928                 case CEE_CONV_OVF_U2:
9929                 case CEE_CONV_OVF_U4:
9930                         CHECK_STACK (1);
9931
9932                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9933                                 ADD_UNOP (CEE_CONV_OVF_U8);
9934                                 ADD_UNOP (*ip);
9935                         } else {
9936                                 ADD_UNOP (*ip);
9937                         }
9938                         ip++;
9939                         break;
9940                 case CEE_CONV_OVF_I1_UN:
9941                 case CEE_CONV_OVF_I2_UN:
9942                 case CEE_CONV_OVF_I4_UN:
9943                 case CEE_CONV_OVF_I8_UN:
9944                 case CEE_CONV_OVF_U1_UN:
9945                 case CEE_CONV_OVF_U2_UN:
9946                 case CEE_CONV_OVF_U4_UN:
9947                 case CEE_CONV_OVF_U8_UN:
9948                 case CEE_CONV_OVF_I_UN:
9949                 case CEE_CONV_OVF_U_UN:
9950                 case CEE_CONV_U2:
9951                 case CEE_CONV_U1:
9952                 case CEE_CONV_I:
9953                 case CEE_CONV_U:
9954                         CHECK_STACK (1);
9955                         ADD_UNOP (*ip);
9956                         CHECK_CFG_EXCEPTION;
9957                         ip++;
9958                         break;
9959                 case CEE_ADD_OVF:
9960                 case CEE_ADD_OVF_UN:
9961                 case CEE_MUL_OVF:
9962                 case CEE_MUL_OVF_UN:
9963                 case CEE_SUB_OVF:
9964                 case CEE_SUB_OVF_UN:
9965                         CHECK_STACK (2);
9966                         ADD_BINOP (*ip);
9967                         ip++;
9968                         break;
9969                 case CEE_CPOBJ:
9970                         GSHAREDVT_FAILURE (*ip);
9971                         CHECK_OPSIZE (5);
9972                         CHECK_STACK (2);
9973                         token = read32 (ip + 1);
9974                         klass = mini_get_class (method, token, generic_context);
9975                         CHECK_TYPELOAD (klass);
9976                         sp -= 2;
9977                         if (generic_class_is_reference_type (cfg, klass)) {
9978                                 MonoInst *store, *load;
9979                                 int dreg = alloc_ireg_ref (cfg);
9980
9981                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9982                                 load->flags |= ins_flag;
9983                                 MONO_ADD_INS (cfg->cbb, load);
9984
9985                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9986                                 store->flags |= ins_flag;
9987                                 MONO_ADD_INS (cfg->cbb, store);
9988
9989                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9990                                         emit_write_barrier (cfg, sp [0], sp [1]);
9991                         } else {
9992                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9993                         }
9994                         ins_flag = 0;
9995                         ip += 5;
9996                         break;
9997                 case CEE_LDOBJ: {
9998                         int loc_index = -1;
9999                         int stloc_len = 0;
10000
10001                         CHECK_OPSIZE (5);
10002                         CHECK_STACK (1);
10003                         --sp;
10004                         token = read32 (ip + 1);
10005                         klass = mini_get_class (method, token, generic_context);
10006                         CHECK_TYPELOAD (klass);
10007
10008                         /* Optimize the common ldobj+stloc combination */
10009                         switch (ip [5]) {
10010                         case CEE_STLOC_S:
10011                                 loc_index = ip [6];
10012                                 stloc_len = 2;
10013                                 break;
10014                         case CEE_STLOC_0:
10015                         case CEE_STLOC_1:
10016                         case CEE_STLOC_2:
10017                         case CEE_STLOC_3:
10018                                 loc_index = ip [5] - CEE_STLOC_0;
10019                                 stloc_len = 1;
10020                                 break;
10021                         default:
10022                                 break;
10023                         }
10024
10025                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10026                                 CHECK_LOCAL (loc_index);
10027
10028                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10029                                 ins->dreg = cfg->locals [loc_index]->dreg;
10030                                 ins->flags |= ins_flag;
10031                                 ip += 5;
10032                                 ip += stloc_len;
10033                                 if (ins_flag & MONO_INST_VOLATILE) {
10034                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10035                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10036                                 }
10037                                 ins_flag = 0;
10038                                 break;
10039                         }
10040
10041                         /* Optimize the ldobj+stobj combination */
10042                         /* The reference case ends up being a load+store anyway */
10043                         /* Skip this if the operation is volatile. */
10044                         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)) {
10045                                 CHECK_STACK (1);
10046
10047                                 sp --;
10048
10049                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10050
10051                                 ip += 5 + 5;
10052                                 ins_flag = 0;
10053                                 break;
10054                         }
10055
10056                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10057                         ins->flags |= ins_flag;
10058                         *sp++ = ins;
10059
10060                         if (ins_flag & MONO_INST_VOLATILE) {
10061                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10062                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10063                         }
10064
10065                         ip += 5;
10066                         ins_flag = 0;
10067                         inline_costs += 1;
10068                         break;
10069                 }
10070                 case CEE_LDSTR:
10071                         CHECK_STACK_OVF (1);
10072                         CHECK_OPSIZE (5);
10073                         n = read32 (ip + 1);
10074
10075                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10076                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10077                                 ins->type = STACK_OBJ;
10078                                 *sp = ins;
10079                         }
10080                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10081                                 MonoInst *iargs [1];
10082                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10083
10084                                 if (cfg->compile_aot)
10085                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10086                                 else
10087                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10088                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10089                         } else {
10090                                 if (cfg->opt & MONO_OPT_SHARED) {
10091                                         MonoInst *iargs [3];
10092
10093                                         if (cfg->compile_aot) {
10094                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10095                                         }
10096                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10097                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10098                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10099                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10100                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10101                                         CHECK_CFG_ERROR;
10102                                 } else {
10103                                         if (cfg->cbb->out_of_line) {
10104                                                 MonoInst *iargs [2];
10105
10106                                                 if (image == mono_defaults.corlib) {
10107                                                         /* 
10108                                                          * Avoid relocations in AOT and save some space by using a 
10109                                                          * version of helper_ldstr specialized to mscorlib.
10110                                                          */
10111                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10112                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10113                                                 } else {
10114                                                         /* Avoid creating the string object */
10115                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10116                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10117                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10118                                                 }
10119                                         } 
10120                                         else
10121                                         if (cfg->compile_aot) {
10122                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10123                                                 *sp = ins;
10124                                                 MONO_ADD_INS (cfg->cbb, ins);
10125                                         } 
10126                                         else {
10127                                                 NEW_PCONST (cfg, ins, NULL);
10128                                                 ins->type = STACK_OBJ;
10129                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10130                                                 CHECK_CFG_ERROR;
10131                                                 
10132                                                 if (!ins->inst_p0)
10133                                                         OUT_OF_MEMORY_FAILURE;
10134
10135                                                 *sp = ins;
10136                                                 MONO_ADD_INS (cfg->cbb, ins);
10137                                         }
10138                                 }
10139                         }
10140
10141                         sp++;
10142                         ip += 5;
10143                         break;
10144                 case CEE_NEWOBJ: {
10145                         MonoInst *iargs [2];
10146                         MonoMethodSignature *fsig;
10147                         MonoInst this_ins;
10148                         MonoInst *alloc;
10149                         MonoInst *vtable_arg = NULL;
10150
10151                         CHECK_OPSIZE (5);
10152                         token = read32 (ip + 1);
10153                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10154                         CHECK_CFG_ERROR;
10155
10156                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10157                         CHECK_CFG_ERROR;
10158
10159                         mono_save_token_info (cfg, image, token, cmethod);
10160
10161                         if (!mono_class_init (cmethod->klass))
10162                                 TYPE_LOAD_ERROR (cmethod->klass);
10163
10164                         context_used = mini_method_check_context_used (cfg, cmethod);
10165
10166                         if (mono_security_core_clr_enabled ())
10167                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10168
10169                         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)) {
10170                                 emit_class_init (cfg, cmethod->klass);
10171                                 CHECK_TYPELOAD (cmethod->klass);
10172                         }
10173
10174                         /*
10175                         if (cfg->gsharedvt) {
10176                                 if (mini_is_gsharedvt_variable_signature (sig))
10177                                         GSHAREDVT_FAILURE (*ip);
10178                         }
10179                         */
10180
10181                         n = fsig->param_count;
10182                         CHECK_STACK (n);
10183
10184                         /* 
10185                          * Generate smaller code for the common newobj <exception> instruction in
10186                          * argument checking code.
10187                          */
10188                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10189                                 is_exception_class (cmethod->klass) && n <= 2 &&
10190                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10191                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10192                                 MonoInst *iargs [3];
10193
10194                                 sp -= n;
10195
10196                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10197                                 switch (n) {
10198                                 case 0:
10199                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10200                                         break;
10201                                 case 1:
10202                                         iargs [1] = sp [0];
10203                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10204                                         break;
10205                                 case 2:
10206                                         iargs [1] = sp [0];
10207                                         iargs [2] = sp [1];
10208                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10209                                         break;
10210                                 default:
10211                                         g_assert_not_reached ();
10212                                 }
10213
10214                                 ip += 5;
10215                                 inline_costs += 5;
10216                                 break;
10217                         }
10218
10219                         /* move the args to allow room for 'this' in the first position */
10220                         while (n--) {
10221                                 --sp;
10222                                 sp [1] = sp [0];
10223                         }
10224
10225                         /* check_call_signature () requires sp[0] to be set */
10226                         this_ins.type = STACK_OBJ;
10227                         sp [0] = &this_ins;
10228                         if (check_call_signature (cfg, fsig, sp))
10229                                 UNVERIFIED;
10230
10231                         iargs [0] = NULL;
10232
10233                         if (mini_class_is_system_array (cmethod->klass)) {
10234                                 *sp = emit_get_rgctx_method (cfg, context_used,
10235                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10236
10237                                 /* Avoid varargs in the common case */
10238                                 if (fsig->param_count == 1)
10239                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10240                                 else if (fsig->param_count == 2)
10241                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10242                                 else if (fsig->param_count == 3)
10243                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10244                                 else if (fsig->param_count == 4)
10245                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10246                                 else
10247                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10248                         } else if (cmethod->string_ctor) {
10249                                 g_assert (!context_used);
10250                                 g_assert (!vtable_arg);
10251                                 /* we simply pass a null pointer */
10252                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10253                                 /* now call the string ctor */
10254                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10255                         } else {
10256                                 if (cmethod->klass->valuetype) {
10257                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10258                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10259                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10260
10261                                         alloc = NULL;
10262
10263                                         /* 
10264                                          * The code generated by mini_emit_virtual_call () expects
10265                                          * iargs [0] to be a boxed instance, but luckily the vcall
10266                                          * will be transformed into a normal call there.
10267                                          */
10268                                 } else if (context_used) {
10269                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10270                                         *sp = alloc;
10271                                 } else {
10272                                         MonoVTable *vtable = NULL;
10273
10274                                         if (!cfg->compile_aot)
10275                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10276                                         CHECK_TYPELOAD (cmethod->klass);
10277
10278                                         /*
10279                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10280                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10281                                          * As a workaround, we call class cctors before allocating objects.
10282                                          */
10283                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10284                                                 emit_class_init (cfg, cmethod->klass);
10285                                                 if (cfg->verbose_level > 2)
10286                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10287                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10288                                         }
10289
10290                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10291                                         *sp = alloc;
10292                                 }
10293                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10294
10295                                 if (alloc)
10296                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10297
10298                                 /* Now call the actual ctor */
10299                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10300                                 CHECK_CFG_EXCEPTION;
10301                         }
10302
10303                         if (alloc == NULL) {
10304                                 /* Valuetype */
10305                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10306                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10307                                 *sp++= ins;
10308                         } else {
10309                                 *sp++ = alloc;
10310                         }
10311                         
10312                         ip += 5;
10313                         inline_costs += 5;
10314                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10315                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10316                         break;
10317                 }
10318                 case CEE_CASTCLASS:
10319                 case CEE_ISINST: {
10320                         CHECK_STACK (1);
10321                         --sp;
10322                         CHECK_OPSIZE (5);
10323                         token = read32 (ip + 1);
10324                         klass = mini_get_class (method, token, generic_context);
10325                         CHECK_TYPELOAD (klass);
10326                         if (sp [0]->type != STACK_OBJ)
10327                                 UNVERIFIED;
10328
10329                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
10330                         ins->dreg = alloc_preg (cfg);
10331                         ins->sreg1 = (*sp)->dreg;
10332                         ins->klass = klass;
10333                         ins->type = STACK_OBJ;
10334                         MONO_ADD_INS (cfg->cbb, ins);
10335
10336                         CHECK_CFG_EXCEPTION;
10337                         *sp++ = ins;
10338                         ip += 5;
10339
10340                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10341                         break;
10342                 }
10343                 case CEE_UNBOX_ANY: {
10344                         MonoInst *res, *addr;
10345
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
10353                         mono_save_token_info (cfg, image, token, klass);
10354
10355                         context_used = mini_class_check_context_used (cfg, klass);
10356
10357                         if (mini_is_gsharedvt_klass (klass)) {
10358                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10359                                 inline_costs += 2;
10360                         } else if (generic_class_is_reference_type (cfg, klass)) {
10361                                 if (MONO_INS_IS_PCONST_NULL (*sp)) {
10362                                         EMIT_NEW_PCONST (cfg, res, NULL);
10363                                         res->type = STACK_OBJ;
10364                                 } else {
10365                                         MONO_INST_NEW (cfg, res, OP_CASTCLASS);
10366                                         res->dreg = alloc_preg (cfg);
10367                                         res->sreg1 = (*sp)->dreg;
10368                                         res->klass = klass;
10369                                         res->type = STACK_OBJ;
10370                                         MONO_ADD_INS (cfg->cbb, res);
10371                                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10372                                 }
10373                         } else if (mono_class_is_nullable (klass)) {
10374                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10375                         } else {
10376                                 addr = handle_unbox (cfg, klass, sp, context_used);
10377                                 /* LDOBJ */
10378                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10379                                 res = ins;
10380                                 inline_costs += 2;
10381                         }
10382
10383                         *sp ++ = res;
10384                         ip += 5;
10385                         break;
10386                 }
10387                 case CEE_BOX: {
10388                         MonoInst *val;
10389                         MonoClass *enum_class;
10390                         MonoMethod *has_flag;
10391
10392                         CHECK_STACK (1);
10393                         --sp;
10394                         val = *sp;
10395                         CHECK_OPSIZE (5);
10396                         token = read32 (ip + 1);
10397                         klass = mini_get_class (method, token, generic_context);
10398                         CHECK_TYPELOAD (klass);
10399
10400                         mono_save_token_info (cfg, image, token, klass);
10401
10402                         context_used = mini_class_check_context_used (cfg, klass);
10403
10404                         if (generic_class_is_reference_type (cfg, klass)) {
10405                                 *sp++ = val;
10406                                 ip += 5;
10407                                 break;
10408                         }
10409
10410                         if (klass == mono_defaults.void_class)
10411                                 UNVERIFIED;
10412                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10413                                 UNVERIFIED;
10414                         /* frequent check in generic code: box (struct), brtrue */
10415
10416                         /*
10417                          * Look for:
10418                          *
10419                          *   <push int/long ptr>
10420                          *   <push int/long>
10421                          *   box MyFlags
10422                          *   constrained. MyFlags
10423                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10424                          *
10425                          * If we find this sequence and the operand types on box and constrained
10426                          * are equal, we can emit a specialized instruction sequence instead of
10427                          * the very slow HasFlag () call.
10428                          */
10429                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10430                             /* Cheap checks first. */
10431                             ip + 5 + 6 + 5 < end &&
10432                             ip [5] == CEE_PREFIX1 &&
10433                             ip [6] == CEE_CONSTRAINED_ &&
10434                             ip [11] == CEE_CALLVIRT &&
10435                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10436                             mono_class_is_enum (klass) &&
10437                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10438                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10439                             has_flag->klass == mono_defaults.enum_class &&
10440                             !strcmp (has_flag->name, "HasFlag") &&
10441                             has_flag->signature->hasthis &&
10442                             has_flag->signature->param_count == 1) {
10443                                 CHECK_TYPELOAD (enum_class);
10444
10445                                 if (enum_class == klass) {
10446                                         MonoInst *enum_this, *enum_flag;
10447
10448                                         ip += 5 + 6 + 5;
10449                                         --sp;
10450
10451                                         enum_this = sp [0];
10452                                         enum_flag = sp [1];
10453
10454                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10455                                         break;
10456                                 }
10457                         }
10458
10459                         // FIXME: LLVM can't handle the inconsistent bb linking
10460                         if (!mono_class_is_nullable (klass) &&
10461                                 !mini_is_gsharedvt_klass (klass) &&
10462                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10463                                 (ip [5] == CEE_BRTRUE || 
10464                                  ip [5] == CEE_BRTRUE_S ||
10465                                  ip [5] == CEE_BRFALSE ||
10466                                  ip [5] == CEE_BRFALSE_S)) {
10467                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10468                                 int dreg;
10469                                 MonoBasicBlock *true_bb, *false_bb;
10470
10471                                 ip += 5;
10472
10473                                 if (cfg->verbose_level > 3) {
10474                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10475                                         printf ("<box+brtrue opt>\n");
10476                                 }
10477
10478                                 switch (*ip) {
10479                                 case CEE_BRTRUE_S:
10480                                 case CEE_BRFALSE_S:
10481                                         CHECK_OPSIZE (2);
10482                                         ip++;
10483                                         target = ip + 1 + (signed char)(*ip);
10484                                         ip++;
10485                                         break;
10486                                 case CEE_BRTRUE:
10487                                 case CEE_BRFALSE:
10488                                         CHECK_OPSIZE (5);
10489                                         ip++;
10490                                         target = ip + 4 + (gint)(read32 (ip));
10491                                         ip += 4;
10492                                         break;
10493                                 default:
10494                                         g_assert_not_reached ();
10495                                 }
10496
10497                                 /* 
10498                                  * We need to link both bblocks, since it is needed for handling stack
10499                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10500                                  * Branching to only one of them would lead to inconsistencies, so
10501                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10502                                  */
10503                                 GET_BBLOCK (cfg, true_bb, target);
10504                                 GET_BBLOCK (cfg, false_bb, ip);
10505
10506                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10507                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10508
10509                                 if (sp != stack_start) {
10510                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10511                                         sp = stack_start;
10512                                         CHECK_UNVERIFIABLE (cfg);
10513                                 }
10514
10515                                 if (COMPILE_LLVM (cfg)) {
10516                                         dreg = alloc_ireg (cfg);
10517                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10518                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10519
10520                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10521                                 } else {
10522                                         /* The JIT can't eliminate the iconst+compare */
10523                                         MONO_INST_NEW (cfg, ins, OP_BR);
10524                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10525                                         MONO_ADD_INS (cfg->cbb, ins);
10526                                 }
10527
10528                                 start_new_bblock = 1;
10529                                 break;
10530                         }
10531
10532                         *sp++ = handle_box (cfg, val, klass, context_used);
10533
10534                         CHECK_CFG_EXCEPTION;
10535                         ip += 5;
10536                         inline_costs += 1;
10537                         break;
10538                 }
10539                 case CEE_UNBOX: {
10540                         CHECK_STACK (1);
10541                         --sp;
10542                         CHECK_OPSIZE (5);
10543                         token = read32 (ip + 1);
10544                         klass = mini_get_class (method, token, generic_context);
10545                         CHECK_TYPELOAD (klass);
10546
10547                         mono_save_token_info (cfg, image, token, klass);
10548
10549                         context_used = mini_class_check_context_used (cfg, klass);
10550
10551                         if (mono_class_is_nullable (klass)) {
10552                                 MonoInst *val;
10553
10554                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10555                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10556
10557                                 *sp++= ins;
10558                         } else {
10559                                 ins = handle_unbox (cfg, klass, sp, context_used);
10560                                 *sp++ = ins;
10561                         }
10562                         ip += 5;
10563                         inline_costs += 2;
10564                         break;
10565                 }
10566                 case CEE_LDFLD:
10567                 case CEE_LDFLDA:
10568                 case CEE_STFLD:
10569                 case CEE_LDSFLD:
10570                 case CEE_LDSFLDA:
10571                 case CEE_STSFLD: {
10572                         MonoClassField *field;
10573 #ifndef DISABLE_REMOTING
10574                         int costs;
10575 #endif
10576                         guint foffset;
10577                         gboolean is_instance;
10578                         int op;
10579                         gpointer addr = NULL;
10580                         gboolean is_special_static;
10581                         MonoType *ftype;
10582                         MonoInst *store_val = NULL;
10583                         MonoInst *thread_ins;
10584
10585                         op = *ip;
10586                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10587                         if (is_instance) {
10588                                 if (op == CEE_STFLD) {
10589                                         CHECK_STACK (2);
10590                                         sp -= 2;
10591                                         store_val = sp [1];
10592                                 } else {
10593                                         CHECK_STACK (1);
10594                                         --sp;
10595                                 }
10596                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10597                                         UNVERIFIED;
10598                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10599                                         UNVERIFIED;
10600                         } else {
10601                                 if (op == CEE_STSFLD) {
10602                                         CHECK_STACK (1);
10603                                         sp--;
10604                                         store_val = sp [0];
10605                                 }
10606                         }
10607
10608                         CHECK_OPSIZE (5);
10609                         token = read32 (ip + 1);
10610                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10611                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
10612                                 klass = field->parent;
10613                         }
10614                         else {
10615                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10616                                 CHECK_CFG_ERROR;
10617                         }
10618                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10619                                 FIELD_ACCESS_FAILURE (method, field);
10620                         mono_class_init (klass);
10621
10622                         /* if the class is Critical then transparent code cannot access it's fields */
10623                         if (!is_instance && mono_security_core_clr_enabled ())
10624                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10625
10626                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10627                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10628                         if (mono_security_core_clr_enabled ())
10629                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10630                         */
10631
10632                         ftype = mono_field_get_type (field);
10633
10634                         /*
10635                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10636                          * the static case.
10637                          */
10638                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
10639                                 switch (op) {
10640                                 case CEE_LDFLD:
10641                                         op = CEE_LDSFLD;
10642                                         break;
10643                                 case CEE_STFLD:
10644                                         op = CEE_STSFLD;
10645                                         break;
10646                                 case CEE_LDFLDA:
10647                                         op = CEE_LDSFLDA;
10648                                         break;
10649                                 default:
10650                                         g_assert_not_reached ();
10651                                 }
10652                                 is_instance = FALSE;
10653                         }
10654
10655                         context_used = mini_class_check_context_used (cfg, klass);
10656
10657                         /* INSTANCE CASE */
10658
10659                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10660                         if (op == CEE_STFLD) {
10661                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10662                                         UNVERIFIED;
10663 #ifndef DISABLE_REMOTING
10664                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10665                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10666                                         MonoInst *iargs [5];
10667
10668                                         GSHAREDVT_FAILURE (op);
10669
10670                                         iargs [0] = sp [0];
10671                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10672                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10673                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10674                                                     field->offset);
10675                                         iargs [4] = sp [1];
10676
10677                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10678                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10679                                                                                            iargs, ip, cfg->real_offset, TRUE);
10680                                                 CHECK_CFG_EXCEPTION;
10681                                                 g_assert (costs > 0);
10682                                                       
10683                                                 cfg->real_offset += 5;
10684
10685                                                 inline_costs += costs;
10686                                         } else {
10687                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10688                                         }
10689                                 } else
10690 #endif
10691                                 {
10692                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
10693
10694                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10695
10696                                         if (ins_flag & MONO_INST_VOLATILE) {
10697                                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10698                                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10699                                         }
10700
10701                                         if (mini_is_gsharedvt_klass (klass)) {
10702                                                 MonoInst *offset_ins;
10703
10704                                                 context_used = mini_class_check_context_used (cfg, klass);
10705
10706                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10707                                                 /* The value is offset by 1 */
10708                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10709                                                 dreg = alloc_ireg_mp (cfg);
10710                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10711                                                 wbarrier_ptr_ins = ins;
10712                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10713                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10714                                         } else {
10715                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10716                                         }
10717                                         if (sp [0]->opcode != OP_LDADDR)
10718                                                 store->flags |= MONO_INST_FAULT;
10719
10720                                         if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
10721                                                 if (mini_is_gsharedvt_klass (klass)) {
10722                                                         g_assert (wbarrier_ptr_ins);
10723                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
10724                                                 } else {
10725                                                         /* insert call to write barrier */
10726                                                         MonoInst *ptr;
10727                                                         int dreg;
10728
10729                                                         dreg = alloc_ireg_mp (cfg);
10730                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10731                                                         emit_write_barrier (cfg, ptr, sp [1]);
10732                                                 }
10733                                         }
10734
10735                                         store->flags |= ins_flag;
10736                                 }
10737                                 ins_flag = 0;
10738                                 ip += 5;
10739                                 break;
10740                         }
10741
10742 #ifndef DISABLE_REMOTING
10743                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10744                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10745                                 MonoInst *iargs [4];
10746
10747                                 GSHAREDVT_FAILURE (op);
10748
10749                                 iargs [0] = sp [0];
10750                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10751                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10752                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10753                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10754                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10755                                                                                    iargs, ip, cfg->real_offset, TRUE);
10756                                         CHECK_CFG_EXCEPTION;
10757                                         g_assert (costs > 0);
10758                                                       
10759                                         cfg->real_offset += 5;
10760
10761                                         *sp++ = iargs [0];
10762
10763                                         inline_costs += costs;
10764                                 } else {
10765                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10766                                         *sp++ = ins;
10767                                 }
10768                         } else 
10769 #endif
10770                         if (is_instance) {
10771                                 if (sp [0]->type == STACK_VTYPE) {
10772                                         MonoInst *var;
10773
10774                                         /* Have to compute the address of the variable */
10775
10776                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10777                                         if (!var)
10778                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10779                                         else
10780                                                 g_assert (var->klass == klass);
10781                                         
10782                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10783                                         sp [0] = ins;
10784                                 }
10785
10786                                 if (op == CEE_LDFLDA) {
10787                                         if (sp [0]->type == STACK_OBJ) {
10788                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10789                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10790                                         }
10791
10792                                         dreg = alloc_ireg_mp (cfg);
10793
10794                                         if (mini_is_gsharedvt_klass (klass)) {
10795                                                 MonoInst *offset_ins;
10796
10797                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10798                                                 /* The value is offset by 1 */
10799                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10800                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10801                                         } else {
10802                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10803                                         }
10804                                         ins->klass = mono_class_from_mono_type (field->type);
10805                                         ins->type = STACK_MP;
10806                                         *sp++ = ins;
10807                                 } else {
10808                                         MonoInst *load;
10809
10810                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10811
10812                                         if (sp [0]->opcode == OP_LDADDR && klass->simd_type && cfg->opt & MONO_OPT_SIMD) {
10813                                                 ins = mono_emit_simd_field_load (cfg, field, sp [0]);
10814                                                 if (ins) {
10815                                                         *sp++ = ins;
10816                                                         ins_flag = 0;
10817                                                         ip += 5;
10818                                                         break;
10819                                                 }
10820                                         }
10821
10822                                         if (mini_is_gsharedvt_klass (klass)) {
10823                                                 MonoInst *offset_ins;
10824
10825                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10826                                                 /* The value is offset by 1 */
10827                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10828                                                 dreg = alloc_ireg_mp (cfg);
10829                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10830                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10831                                         } else {
10832                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10833                                         }
10834                                         load->flags |= ins_flag;
10835                                         if (sp [0]->opcode != OP_LDADDR)
10836                                                 load->flags |= MONO_INST_FAULT;
10837                                         *sp++ = load;
10838                                 }
10839                         }
10840
10841                         if (is_instance) {
10842                                 ins_flag = 0;
10843                                 ip += 5;
10844                                 break;
10845                         }
10846
10847                         /* STATIC CASE */
10848                         context_used = mini_class_check_context_used (cfg, klass);
10849
10850                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
10851                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
10852                                 CHECK_CFG_ERROR;
10853                         }
10854
10855                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10856                          * to be called here.
10857                          */
10858                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10859                                 mono_class_vtable (cfg->domain, klass);
10860                                 CHECK_TYPELOAD (klass);
10861                         }
10862                         mono_domain_lock (cfg->domain);
10863                         if (cfg->domain->special_static_fields)
10864                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10865                         mono_domain_unlock (cfg->domain);
10866
10867                         is_special_static = mono_class_field_is_special_static (field);
10868
10869                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10870                                 thread_ins = mono_create_tls_get (cfg, TLS_KEY_THREAD);
10871                         else
10872                                 thread_ins = NULL;
10873
10874                         /* Generate IR to compute the field address */
10875                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10876                                 /*
10877                                  * Fast access to TLS data
10878                                  * Inline version of get_thread_static_data () in
10879                                  * threads.c.
10880                                  */
10881                                 guint32 offset;
10882                                 int idx, static_data_reg, array_reg, dreg;
10883
10884                                 if (context_used && cfg->gsharedvt && mini_is_gsharedvt_klass (klass))
10885                                         GSHAREDVT_FAILURE (op);
10886
10887                                 static_data_reg = alloc_ireg (cfg);
10888                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
10889
10890                                 if (cfg->compile_aot) {
10891                                         int offset_reg, offset2_reg, idx_reg;
10892
10893                                         /* For TLS variables, this will return the TLS offset */
10894                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10895                                         offset_reg = ins->dreg;
10896                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10897                                         idx_reg = alloc_ireg (cfg);
10898                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
10899                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10900                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10901                                         array_reg = alloc_ireg (cfg);
10902                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10903                                         offset2_reg = alloc_ireg (cfg);
10904                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
10905                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
10906                                         dreg = alloc_ireg (cfg);
10907                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10908                                 } else {
10909                                         offset = (gsize)addr & 0x7fffffff;
10910                                         idx = offset & 0x3f;
10911
10912                                         array_reg = alloc_ireg (cfg);
10913                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10914                                         dreg = alloc_ireg (cfg);
10915                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
10916                                 }
10917                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10918                                         (cfg->compile_aot && is_special_static) ||
10919                                         (context_used && is_special_static)) {
10920                                 MonoInst *iargs [2];
10921
10922                                 g_assert (field->parent);
10923                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10924                                 if (context_used) {
10925                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10926                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10927                                 } else {
10928                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10929                                 }
10930                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10931                         } else if (context_used) {
10932                                 MonoInst *static_data;
10933
10934                                 /*
10935                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10936                                         method->klass->name_space, method->klass->name, method->name,
10937                                         depth, field->offset);
10938                                 */
10939
10940                                 if (mono_class_needs_cctor_run (klass, method))
10941                                         emit_class_init (cfg, klass);
10942
10943                                 /*
10944                                  * The pointer we're computing here is
10945                                  *
10946                                  *   super_info.static_data + field->offset
10947                                  */
10948                                 static_data = mini_emit_get_rgctx_klass (cfg, context_used,
10949                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10950
10951                                 if (mini_is_gsharedvt_klass (klass)) {
10952                                         MonoInst *offset_ins;
10953
10954                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10955                                         /* The value is offset by 1 */
10956                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10957                                         dreg = alloc_ireg_mp (cfg);
10958                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10959                                 } else if (field->offset == 0) {
10960                                         ins = static_data;
10961                                 } else {
10962                                         int addr_reg = mono_alloc_preg (cfg);
10963                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10964                                 }
10965                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10966                                 MonoInst *iargs [2];
10967
10968                                 g_assert (field->parent);
10969                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10970                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10971                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10972                         } else {
10973                                 MonoVTable *vtable = NULL;
10974
10975                                 if (!cfg->compile_aot)
10976                                         vtable = mono_class_vtable (cfg->domain, klass);
10977                                 CHECK_TYPELOAD (klass);
10978
10979                                 if (!addr) {
10980                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10981                                                 if (!(g_slist_find (class_inits, klass))) {
10982                                                         emit_class_init (cfg, klass);
10983                                                         if (cfg->verbose_level > 2)
10984                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10985                                                         class_inits = g_slist_prepend (class_inits, klass);
10986                                                 }
10987                                         } else {
10988                                                 if (cfg->run_cctors) {
10989                                                         /* This makes so that inline cannot trigger */
10990                                                         /* .cctors: too many apps depend on them */
10991                                                         /* running with a specific order... */
10992                                                         g_assert (vtable);
10993                                                         if (! vtable->initialized)
10994                                                                 INLINE_FAILURE ("class init");
10995                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
10996                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
10997                                                                 goto exception_exit;
10998                                                         }
10999                                                 }
11000                                         }
11001                                         if (cfg->compile_aot)
11002                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11003                                         else {
11004                                                 g_assert (vtable);
11005                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11006                                                 g_assert (addr);
11007                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11008                                         }
11009                                 } else {
11010                                         MonoInst *iargs [1];
11011                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11012                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11013                                 }
11014                         }
11015
11016                         /* Generate IR to do the actual load/store operation */
11017
11018                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11019                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11020                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11021                         }
11022
11023                         if (op == CEE_LDSFLDA) {
11024                                 ins->klass = mono_class_from_mono_type (ftype);
11025                                 ins->type = STACK_PTR;
11026                                 *sp++ = ins;
11027                         } else if (op == CEE_STSFLD) {
11028                                 MonoInst *store;
11029
11030                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11031                                 store->flags |= ins_flag;
11032                         } else {
11033                                 gboolean is_const = FALSE;
11034                                 MonoVTable *vtable = NULL;
11035                                 gpointer addr = NULL;
11036
11037                                 if (!context_used) {
11038                                         vtable = mono_class_vtable (cfg->domain, klass);
11039                                         CHECK_TYPELOAD (klass);
11040                                 }
11041                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11042                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11043                                         int ro_type = ftype->type;
11044                                         if (!addr)
11045                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11046                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11047                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11048                                         }
11049
11050                                         GSHAREDVT_FAILURE (op);
11051
11052                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11053                                         is_const = TRUE;
11054                                         switch (ro_type) {
11055                                         case MONO_TYPE_BOOLEAN:
11056                                         case MONO_TYPE_U1:
11057                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11058                                                 sp++;
11059                                                 break;
11060                                         case MONO_TYPE_I1:
11061                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11062                                                 sp++;
11063                                                 break;                                          
11064                                         case MONO_TYPE_CHAR:
11065                                         case MONO_TYPE_U2:
11066                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11067                                                 sp++;
11068                                                 break;
11069                                         case MONO_TYPE_I2:
11070                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11071                                                 sp++;
11072                                                 break;
11073                                                 break;
11074                                         case MONO_TYPE_I4:
11075                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11076                                                 sp++;
11077                                                 break;                                          
11078                                         case MONO_TYPE_U4:
11079                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11080                                                 sp++;
11081                                                 break;
11082                                         case MONO_TYPE_I:
11083                                         case MONO_TYPE_U:
11084                                         case MONO_TYPE_PTR:
11085                                         case MONO_TYPE_FNPTR:
11086                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11087                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11088                                                 sp++;
11089                                                 break;
11090                                         case MONO_TYPE_STRING:
11091                                         case MONO_TYPE_OBJECT:
11092                                         case MONO_TYPE_CLASS:
11093                                         case MONO_TYPE_SZARRAY:
11094                                         case MONO_TYPE_ARRAY:
11095                                                 if (!mono_gc_is_moving ()) {
11096                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11097                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11098                                                         sp++;
11099                                                 } else {
11100                                                         is_const = FALSE;
11101                                                 }
11102                                                 break;
11103                                         case MONO_TYPE_I8:
11104                                         case MONO_TYPE_U8:
11105                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11106                                                 sp++;
11107                                                 break;
11108                                         case MONO_TYPE_R4:
11109                                         case MONO_TYPE_R8:
11110                                         case MONO_TYPE_VALUETYPE:
11111                                         default:
11112                                                 is_const = FALSE;
11113                                                 break;
11114                                         }
11115                                 }
11116
11117                                 if (!is_const) {
11118                                         MonoInst *load;
11119
11120                                         CHECK_STACK_OVF (1);
11121
11122                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11123                                         load->flags |= ins_flag;
11124                                         ins_flag = 0;
11125                                         *sp++ = load;
11126                                 }
11127                         }
11128
11129                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11130                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11131                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11132                         }
11133
11134                         ins_flag = 0;
11135                         ip += 5;
11136                         break;
11137                 }
11138                 case CEE_STOBJ:
11139                         CHECK_STACK (2);
11140                         sp -= 2;
11141                         CHECK_OPSIZE (5);
11142                         token = read32 (ip + 1);
11143                         klass = mini_get_class (method, token, generic_context);
11144                         CHECK_TYPELOAD (klass);
11145                         if (ins_flag & MONO_INST_VOLATILE) {
11146                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11147                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11148                         }
11149                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11150                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11151                         ins->flags |= ins_flag;
11152                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11153                                 generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
11154                                 /* insert call to write barrier */
11155                                 emit_write_barrier (cfg, sp [0], sp [1]);
11156                         }
11157                         ins_flag = 0;
11158                         ip += 5;
11159                         inline_costs += 1;
11160                         break;
11161
11162                         /*
11163                          * Array opcodes
11164                          */
11165                 case CEE_NEWARR: {
11166                         MonoInst *len_ins;
11167                         const char *data_ptr;
11168                         int data_size = 0;
11169                         guint32 field_token;
11170
11171                         CHECK_STACK (1);
11172                         --sp;
11173
11174                         CHECK_OPSIZE (5);
11175                         token = read32 (ip + 1);
11176
11177                         klass = mini_get_class (method, token, generic_context);
11178                         CHECK_TYPELOAD (klass);
11179
11180                         context_used = mini_class_check_context_used (cfg, klass);
11181
11182                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11183                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11184                                 ins->sreg1 = sp [0]->dreg;
11185                                 ins->type = STACK_I4;
11186                                 ins->dreg = alloc_ireg (cfg);
11187                                 MONO_ADD_INS (cfg->cbb, ins);
11188                                 *sp = mono_decompose_opcode (cfg, ins);
11189                         }
11190
11191                         if (context_used) {
11192                                 MonoInst *args [3];
11193                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11194                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11195
11196                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11197
11198                                 /* vtable */
11199                                 args [0] = mini_emit_get_rgctx_klass (cfg, context_used,
11200                                         array_class, MONO_RGCTX_INFO_VTABLE);
11201                                 /* array len */
11202                                 args [1] = sp [0];
11203
11204                                 if (managed_alloc)
11205                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11206                                 else
11207                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11208                         } else {
11209                                 if (cfg->opt & MONO_OPT_SHARED) {
11210                                         /* Decompose now to avoid problems with references to the domainvar */
11211                                         MonoInst *iargs [3];
11212
11213                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11214                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11215                                         iargs [2] = sp [0];
11216
11217                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11218                                 } else {
11219                                         /* Decompose later since it is needed by abcrem */
11220                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11221                                         mono_class_vtable (cfg->domain, array_type);
11222                                         CHECK_TYPELOAD (array_type);
11223
11224                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11225                                         ins->dreg = alloc_ireg_ref (cfg);
11226                                         ins->sreg1 = sp [0]->dreg;
11227                                         ins->inst_newa_class = klass;
11228                                         ins->type = STACK_OBJ;
11229                                         ins->klass = array_type;
11230                                         MONO_ADD_INS (cfg->cbb, ins);
11231                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11232                                         cfg->cbb->has_array_access = TRUE;
11233
11234                                         /* Needed so mono_emit_load_get_addr () gets called */
11235                                         mono_get_got_var (cfg);
11236                                 }
11237                         }
11238
11239                         len_ins = sp [0];
11240                         ip += 5;
11241                         *sp++ = ins;
11242                         inline_costs += 1;
11243
11244                         /* 
11245                          * we inline/optimize the initialization sequence if possible.
11246                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11247                          * for small sizes open code the memcpy
11248                          * ensure the rva field is big enough
11249                          */
11250                         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))) {
11251                                 MonoMethod *memcpy_method = get_memcpy_method ();
11252                                 MonoInst *iargs [3];
11253                                 int add_reg = alloc_ireg_mp (cfg);
11254
11255                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11256                                 if (cfg->compile_aot) {
11257                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11258                                 } else {
11259                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11260                                 }
11261                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11262                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11263                                 ip += 11;
11264                         }
11265
11266                         break;
11267                 }
11268                 case CEE_LDLEN:
11269                         CHECK_STACK (1);
11270                         --sp;
11271                         if (sp [0]->type != STACK_OBJ)
11272                                 UNVERIFIED;
11273
11274                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11275                         ins->dreg = alloc_preg (cfg);
11276                         ins->sreg1 = sp [0]->dreg;
11277                         ins->type = STACK_I4;
11278                         /* This flag will be inherited by the decomposition */
11279                         ins->flags |= MONO_INST_FAULT;
11280                         MONO_ADD_INS (cfg->cbb, ins);
11281                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11282                         cfg->cbb->has_array_access = TRUE;
11283                         ip ++;
11284                         *sp++ = ins;
11285                         break;
11286                 case CEE_LDELEMA:
11287                         CHECK_STACK (2);
11288                         sp -= 2;
11289                         CHECK_OPSIZE (5);
11290                         if (sp [0]->type != STACK_OBJ)
11291                                 UNVERIFIED;
11292
11293                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11294
11295                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11296                         CHECK_TYPELOAD (klass);
11297                         /* we need to make sure that this array is exactly the type it needs
11298                          * to be for correctness. the wrappers are lax with their usage
11299                          * so we need to ignore them here
11300                          */
11301                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11302                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11303                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11304                                 CHECK_TYPELOAD (array_class);
11305                         }
11306
11307                         readonly = FALSE;
11308                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11309                         *sp++ = ins;
11310                         ip += 5;
11311                         break;
11312                 case CEE_LDELEM:
11313                 case CEE_LDELEM_I1:
11314                 case CEE_LDELEM_U1:
11315                 case CEE_LDELEM_I2:
11316                 case CEE_LDELEM_U2:
11317                 case CEE_LDELEM_I4:
11318                 case CEE_LDELEM_U4:
11319                 case CEE_LDELEM_I8:
11320                 case CEE_LDELEM_I:
11321                 case CEE_LDELEM_R4:
11322                 case CEE_LDELEM_R8:
11323                 case CEE_LDELEM_REF: {
11324                         MonoInst *addr;
11325
11326                         CHECK_STACK (2);
11327                         sp -= 2;
11328
11329                         if (*ip == CEE_LDELEM) {
11330                                 CHECK_OPSIZE (5);
11331                                 token = read32 (ip + 1);
11332                                 klass = mini_get_class (method, token, generic_context);
11333                                 CHECK_TYPELOAD (klass);
11334                                 mono_class_init (klass);
11335                         }
11336                         else
11337                                 klass = array_access_to_klass (*ip);
11338
11339                         if (sp [0]->type != STACK_OBJ)
11340                                 UNVERIFIED;
11341
11342                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11343
11344                         if (mini_is_gsharedvt_variable_klass (klass)) {
11345                                 // FIXME-VT: OP_ICONST optimization
11346                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11347                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11348                                 ins->opcode = OP_LOADV_MEMBASE;
11349                         } else if (sp [1]->opcode == OP_ICONST) {
11350                                 int array_reg = sp [0]->dreg;
11351                                 int index_reg = sp [1]->dreg;
11352                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11353
11354                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
11355                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
11356
11357                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11358                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11359                         } else {
11360                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11361                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11362                         }
11363                         *sp++ = ins;
11364                         if (*ip == CEE_LDELEM)
11365                                 ip += 5;
11366                         else
11367                                 ++ip;
11368                         break;
11369                 }
11370                 case CEE_STELEM_I:
11371                 case CEE_STELEM_I1:
11372                 case CEE_STELEM_I2:
11373                 case CEE_STELEM_I4:
11374                 case CEE_STELEM_I8:
11375                 case CEE_STELEM_R4:
11376                 case CEE_STELEM_R8:
11377                 case CEE_STELEM_REF:
11378                 case CEE_STELEM: {
11379                         CHECK_STACK (3);
11380                         sp -= 3;
11381
11382                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11383
11384                         if (*ip == CEE_STELEM) {
11385                                 CHECK_OPSIZE (5);
11386                                 token = read32 (ip + 1);
11387                                 klass = mini_get_class (method, token, generic_context);
11388                                 CHECK_TYPELOAD (klass);
11389                                 mono_class_init (klass);
11390                         }
11391                         else
11392                                 klass = array_access_to_klass (*ip);
11393
11394                         if (sp [0]->type != STACK_OBJ)
11395                                 UNVERIFIED;
11396
11397                         emit_array_store (cfg, klass, sp, TRUE);
11398
11399                         if (*ip == CEE_STELEM)
11400                                 ip += 5;
11401                         else
11402                                 ++ip;
11403                         inline_costs += 1;
11404                         break;
11405                 }
11406                 case CEE_CKFINITE: {
11407                         CHECK_STACK (1);
11408                         --sp;
11409
11410                         if (cfg->llvm_only) {
11411                                 MonoInst *iargs [1];
11412
11413                                 iargs [0] = sp [0];
11414                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11415                         } else  {
11416                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11417                                 ins->sreg1 = sp [0]->dreg;
11418                                 ins->dreg = alloc_freg (cfg);
11419                                 ins->type = STACK_R8;
11420                                 MONO_ADD_INS (cfg->cbb, ins);
11421
11422                                 *sp++ = mono_decompose_opcode (cfg, ins);
11423                         }
11424
11425                         ++ip;
11426                         break;
11427                 }
11428                 case CEE_REFANYVAL: {
11429                         MonoInst *src_var, *src;
11430
11431                         int klass_reg = alloc_preg (cfg);
11432                         int dreg = alloc_preg (cfg);
11433
11434                         GSHAREDVT_FAILURE (*ip);
11435
11436                         CHECK_STACK (1);
11437                         MONO_INST_NEW (cfg, ins, *ip);
11438                         --sp;
11439                         CHECK_OPSIZE (5);
11440                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11441                         CHECK_TYPELOAD (klass);
11442
11443                         context_used = mini_class_check_context_used (cfg, klass);
11444
11445                         // FIXME:
11446                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11447                         if (!src_var)
11448                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11449                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11450                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11451
11452                         if (context_used) {
11453                                 MonoInst *klass_ins;
11454
11455                                 klass_ins = mini_emit_get_rgctx_klass (cfg, context_used,
11456                                                 klass, MONO_RGCTX_INFO_KLASS);
11457
11458                                 // FIXME:
11459                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11460                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11461                         } else {
11462                                 mini_emit_class_check (cfg, klass_reg, klass);
11463                         }
11464                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11465                         ins->type = STACK_MP;
11466                         ins->klass = klass;
11467                         *sp++ = ins;
11468                         ip += 5;
11469                         break;
11470                 }
11471                 case CEE_MKREFANY: {
11472                         MonoInst *loc, *addr;
11473
11474                         GSHAREDVT_FAILURE (*ip);
11475
11476                         CHECK_STACK (1);
11477                         MONO_INST_NEW (cfg, ins, *ip);
11478                         --sp;
11479                         CHECK_OPSIZE (5);
11480                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11481                         CHECK_TYPELOAD (klass);
11482
11483                         context_used = mini_class_check_context_used (cfg, klass);
11484
11485                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11486                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11487
11488                         if (context_used) {
11489                                 MonoInst *const_ins;
11490                                 int type_reg = alloc_preg (cfg);
11491
11492                                 const_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11493                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11494                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11495                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11496                         } else {
11497                                 int const_reg = alloc_preg (cfg);
11498                                 int type_reg = alloc_preg (cfg);
11499
11500                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11501                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11502                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11503                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11504                         }
11505                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11506
11507                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11508                         ins->type = STACK_VTYPE;
11509                         ins->klass = mono_defaults.typed_reference_class;
11510                         *sp++ = ins;
11511                         ip += 5;
11512                         break;
11513                 }
11514                 case CEE_LDTOKEN: {
11515                         gpointer handle;
11516                         MonoClass *handle_class;
11517
11518                         CHECK_STACK_OVF (1);
11519
11520                         CHECK_OPSIZE (5);
11521                         n = read32 (ip + 1);
11522
11523                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11524                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11525                                 handle = mono_method_get_wrapper_data (method, n);
11526                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
11527                                 if (handle_class == mono_defaults.typehandle_class)
11528                                         handle = &((MonoClass*)handle)->byval_arg;
11529                         }
11530                         else {
11531                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11532                                 CHECK_CFG_ERROR;
11533                         }
11534                         if (!handle)
11535                                 LOAD_ERROR;
11536                         mono_class_init (handle_class);
11537                         if (cfg->gshared) {
11538                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11539                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11540                                         /* This case handles ldtoken
11541                                            of an open type, like for
11542                                            typeof(Gen<>). */
11543                                         context_used = 0;
11544                                 } else if (handle_class == mono_defaults.typehandle_class) {
11545                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
11546                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11547                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11548                                 else if (handle_class == mono_defaults.methodhandle_class)
11549                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
11550                                 else
11551                                         g_assert_not_reached ();
11552                         }
11553
11554                         if ((cfg->opt & MONO_OPT_SHARED) &&
11555                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11556                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11557                                 MonoInst *addr, *vtvar, *iargs [3];
11558                                 int method_context_used;
11559
11560                                 method_context_used = mini_method_check_context_used (cfg, method);
11561
11562                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11563
11564                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11565                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11566                                 if (method_context_used) {
11567                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11568                                                 method, MONO_RGCTX_INFO_METHOD);
11569                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11570                                 } else {
11571                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11572                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11573                                 }
11574                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11575
11576                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11577
11578                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11579                         } else {
11580                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11581                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11582                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11583                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11584                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11585                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
11586
11587                                         mono_class_init (tclass);
11588                                         if (context_used) {
11589                                                 ins = mini_emit_get_rgctx_klass (cfg, context_used,
11590                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11591                                         } else if (cfg->compile_aot) {
11592                                                 if (method->wrapper_type) {
11593                                                         error_init (&error); //got to do it since there are multiple conditionals below
11594                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11595                                                                 /* Special case for static synchronized wrappers */
11596                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11597                                                         } else {
11598                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11599                                                                 /* FIXME: n is not a normal token */
11600                                                                 DISABLE_AOT (cfg);
11601                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11602                                                         }
11603                                                 } else {
11604                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11605                                                 }
11606                                         } else {
11607                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
11608                                                 CHECK_CFG_ERROR;
11609                                                 EMIT_NEW_PCONST (cfg, ins, rt);
11610                                         }
11611                                         ins->type = STACK_OBJ;
11612                                         ins->klass = cmethod->klass;
11613                                         ip += 5;
11614                                 } else {
11615                                         MonoInst *addr, *vtvar;
11616
11617                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11618
11619                                         if (context_used) {
11620                                                 if (handle_class == mono_defaults.typehandle_class) {
11621                                                         ins = mini_emit_get_rgctx_klass (cfg, context_used,
11622                                                                         mono_class_from_mono_type ((MonoType *)handle),
11623                                                                         MONO_RGCTX_INFO_TYPE);
11624                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11625                                                         ins = emit_get_rgctx_method (cfg, context_used,
11626                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
11627                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11628                                                         ins = emit_get_rgctx_field (cfg, context_used,
11629                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
11630                                                 } else {
11631                                                         g_assert_not_reached ();
11632                                                 }
11633                                         } else if (cfg->compile_aot) {
11634                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11635                                         } else {
11636                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11637                                         }
11638                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11639                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11640                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11641                                 }
11642                         }
11643
11644                         *sp++ = ins;
11645                         ip += 5;
11646                         break;
11647                 }
11648                 case CEE_THROW:
11649                         CHECK_STACK (1);
11650                         if (sp [-1]->type != STACK_OBJ)
11651                                 UNVERIFIED;
11652
11653                         MONO_INST_NEW (cfg, ins, OP_THROW);
11654                         --sp;
11655                         ins->sreg1 = sp [0]->dreg;
11656                         ip++;
11657                         cfg->cbb->out_of_line = TRUE;
11658                         MONO_ADD_INS (cfg->cbb, ins);
11659                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11660                         MONO_ADD_INS (cfg->cbb, ins);
11661                         sp = stack_start;
11662                         
11663                         link_bblock (cfg, cfg->cbb, end_bblock);
11664                         start_new_bblock = 1;
11665                         /* This can complicate code generation for llvm since the return value might not be defined */
11666                         if (COMPILE_LLVM (cfg))
11667                                 INLINE_FAILURE ("throw");
11668                         break;
11669                 case CEE_ENDFINALLY:
11670                         if (!ip_in_finally_clause (cfg, ip - header->code))
11671                                 UNVERIFIED;
11672                         /* mono_save_seq_point_info () depends on this */
11673                         if (sp != stack_start)
11674                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11675                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11676                         MONO_ADD_INS (cfg->cbb, ins);
11677                         ip++;
11678                         start_new_bblock = 1;
11679
11680                         /*
11681                          * Control will leave the method so empty the stack, otherwise
11682                          * the next basic block will start with a nonempty stack.
11683                          */
11684                         while (sp != stack_start) {
11685                                 sp--;
11686                         }
11687                         break;
11688                 case CEE_LEAVE:
11689                 case CEE_LEAVE_S: {
11690                         GList *handlers;
11691
11692                         if (*ip == CEE_LEAVE) {
11693                                 CHECK_OPSIZE (5);
11694                                 target = ip + 5 + (gint32)read32(ip + 1);
11695                         } else {
11696                                 CHECK_OPSIZE (2);
11697                                 target = ip + 2 + (signed char)(ip [1]);
11698                         }
11699
11700                         /* empty the stack */
11701                         while (sp != stack_start) {
11702                                 sp--;
11703                         }
11704
11705                         /* 
11706                          * If this leave statement is in a catch block, check for a
11707                          * pending exception, and rethrow it if necessary.
11708                          * We avoid doing this in runtime invoke wrappers, since those are called
11709                          * by native code which excepts the wrapper to catch all exceptions.
11710                          */
11711                         for (i = 0; i < header->num_clauses; ++i) {
11712                                 MonoExceptionClause *clause = &header->clauses [i];
11713
11714                                 /* 
11715                                  * Use <= in the final comparison to handle clauses with multiple
11716                                  * leave statements, like in bug #78024.
11717                                  * The ordering of the exception clauses guarantees that we find the
11718                                  * innermost clause.
11719                                  */
11720                                 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) {
11721                                         MonoInst *exc_ins;
11722                                         MonoBasicBlock *dont_throw;
11723
11724                                         /*
11725                                           MonoInst *load;
11726
11727                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11728                                         */
11729
11730                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11731
11732                                         NEW_BBLOCK (cfg, dont_throw);
11733
11734                                         /*
11735                                          * Currently, we always rethrow the abort exception, despite the 
11736                                          * fact that this is not correct. See thread6.cs for an example. 
11737                                          * But propagating the abort exception is more important than 
11738                                          * getting the sematics right.
11739                                          */
11740                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11741                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11742                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11743
11744                                         MONO_START_BB (cfg, dont_throw);
11745                                 }
11746                         }
11747
11748 #ifdef ENABLE_LLVM
11749                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
11750 #endif
11751
11752                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11753                                 GList *tmp;
11754                                 MonoExceptionClause *clause;
11755
11756                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11757                                         clause = (MonoExceptionClause *)tmp->data;
11758                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11759                                         g_assert (tblock);
11760                                         link_bblock (cfg, cfg->cbb, tblock);
11761                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11762                                         ins->inst_target_bb = tblock;
11763                                         ins->inst_eh_block = clause;
11764                                         MONO_ADD_INS (cfg->cbb, ins);
11765                                         cfg->cbb->has_call_handler = 1;
11766                                         if (COMPILE_LLVM (cfg)) {
11767                                                 MonoBasicBlock *target_bb;
11768
11769                                                 /* 
11770                                                  * Link the finally bblock with the target, since it will
11771                                                  * conceptually branch there.
11772                                                  */
11773                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
11774                                                 GET_BBLOCK (cfg, target_bb, target);
11775                                                 link_bblock (cfg, tblock, target_bb);
11776                                         }
11777                                 }
11778                                 g_list_free (handlers);
11779                         } 
11780
11781                         MONO_INST_NEW (cfg, ins, OP_BR);
11782                         MONO_ADD_INS (cfg->cbb, ins);
11783                         GET_BBLOCK (cfg, tblock, target);
11784                         link_bblock (cfg, cfg->cbb, tblock);
11785                         ins->inst_target_bb = tblock;
11786
11787                         start_new_bblock = 1;
11788
11789                         if (*ip == CEE_LEAVE)
11790                                 ip += 5;
11791                         else
11792                                 ip += 2;
11793
11794                         break;
11795                 }
11796
11797                         /*
11798                          * Mono specific opcodes
11799                          */
11800                 case MONO_CUSTOM_PREFIX: {
11801
11802                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11803
11804                         CHECK_OPSIZE (2);
11805                         switch (ip [1]) {
11806                         case CEE_MONO_ICALL: {
11807                                 gpointer func;
11808                                 MonoJitICallInfo *info;
11809
11810                                 token = read32 (ip + 2);
11811                                 func = mono_method_get_wrapper_data (method, token);
11812                                 info = mono_find_jit_icall_by_addr (func);
11813                                 if (!info)
11814                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11815                                 g_assert (info);
11816
11817                                 CHECK_STACK (info->sig->param_count);
11818                                 sp -= info->sig->param_count;
11819
11820                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11821                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11822                                         *sp++ = ins;
11823
11824                                 ip += 6;
11825                                 inline_costs += 10 * num_calls++;
11826
11827                                 break;
11828                         }
11829                         case CEE_MONO_LDPTR_CARD_TABLE:
11830                         case CEE_MONO_LDPTR_NURSERY_START:
11831                         case CEE_MONO_LDPTR_NURSERY_BITS:
11832                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
11833                                 CHECK_STACK_OVF (1);
11834
11835                                 switch (ip [1]) {
11836                                         case CEE_MONO_LDPTR_CARD_TABLE:
11837                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
11838                                                 break;
11839                                         case CEE_MONO_LDPTR_NURSERY_START:
11840                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
11841                                                 break;
11842                                         case CEE_MONO_LDPTR_NURSERY_BITS:
11843                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
11844                                                 break;
11845                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
11846                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11847                                                 break;
11848                                 }
11849
11850                                 *sp++ = ins;
11851                                 ip += 2;
11852                                 inline_costs += 10 * num_calls++;
11853                                 break;
11854                         }
11855                         case CEE_MONO_LDPTR: {
11856                                 gpointer ptr;
11857
11858                                 CHECK_STACK_OVF (1);
11859                                 CHECK_OPSIZE (6);
11860                                 token = read32 (ip + 2);
11861
11862                                 ptr = mono_method_get_wrapper_data (method, token);
11863                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11864                                 *sp++ = ins;
11865                                 ip += 6;
11866                                 inline_costs += 10 * num_calls++;
11867                                 /* Can't embed random pointers into AOT code */
11868                                 DISABLE_AOT (cfg);
11869                                 break;
11870                         }
11871                         case CEE_MONO_JIT_ICALL_ADDR: {
11872                                 MonoJitICallInfo *callinfo;
11873                                 gpointer ptr;
11874
11875                                 CHECK_STACK_OVF (1);
11876                                 CHECK_OPSIZE (6);
11877                                 token = read32 (ip + 2);
11878
11879                                 ptr = mono_method_get_wrapper_data (method, token);
11880                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11881                                 g_assert (callinfo);
11882                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11883                                 *sp++ = ins;
11884                                 ip += 6;
11885                                 inline_costs += 10 * num_calls++;
11886                                 break;
11887                         }
11888                         case CEE_MONO_ICALL_ADDR: {
11889                                 MonoMethod *cmethod;
11890                                 gpointer ptr;
11891
11892                                 CHECK_STACK_OVF (1);
11893                                 CHECK_OPSIZE (6);
11894                                 token = read32 (ip + 2);
11895
11896                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
11897
11898                                 if (cfg->compile_aot) {
11899                                         if (cfg->direct_pinvoke && ip + 6 < end && (ip [6] == CEE_POP)) {
11900                                                 /*
11901                                                  * This is generated by emit_native_wrapper () to resolve the pinvoke address
11902                                                  * before the call, its not needed when using direct pinvoke.
11903                                                  * This is not an optimization, but its used to avoid looking up pinvokes
11904                                                  * on platforms which don't support dlopen ().
11905                                                  */
11906                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11907                                         } else {
11908                                                 EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11909                                         }
11910                                 } else {
11911                                         ptr = mono_lookup_internal_call (cmethod);
11912                                         g_assert (ptr);
11913                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11914                                 }
11915                                 *sp++ = ins;
11916                                 ip += 6;
11917                                 break;
11918                         }
11919                         case CEE_MONO_VTADDR: {
11920                                 MonoInst *src_var, *src;
11921
11922                                 CHECK_STACK (1);
11923                                 --sp;
11924
11925                                 // FIXME:
11926                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11927                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11928                                 *sp++ = src;
11929                                 ip += 2;
11930                                 break;
11931                         }
11932                         case CEE_MONO_NEWOBJ: {
11933                                 MonoInst *iargs [2];
11934
11935                                 CHECK_STACK_OVF (1);
11936                                 CHECK_OPSIZE (6);
11937                                 token = read32 (ip + 2);
11938                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11939                                 mono_class_init (klass);
11940                                 NEW_DOMAINCONST (cfg, iargs [0]);
11941                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11942                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11943                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11944                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
11945                                 ip += 6;
11946                                 inline_costs += 10 * num_calls++;
11947                                 break;
11948                         }
11949                         case CEE_MONO_OBJADDR:
11950                                 CHECK_STACK (1);
11951                                 --sp;
11952                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11953                                 ins->dreg = alloc_ireg_mp (cfg);
11954                                 ins->sreg1 = sp [0]->dreg;
11955                                 ins->type = STACK_MP;
11956                                 MONO_ADD_INS (cfg->cbb, ins);
11957                                 *sp++ = ins;
11958                                 ip += 2;
11959                                 break;
11960                         case CEE_MONO_LDNATIVEOBJ:
11961                                 /*
11962                                  * Similar to LDOBJ, but instead load the unmanaged 
11963                                  * representation of the vtype to the stack.
11964                                  */
11965                                 CHECK_STACK (1);
11966                                 CHECK_OPSIZE (6);
11967                                 --sp;
11968                                 token = read32 (ip + 2);
11969                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11970                                 g_assert (klass->valuetype);
11971                                 mono_class_init (klass);
11972
11973                                 {
11974                                         MonoInst *src, *dest, *temp;
11975
11976                                         src = sp [0];
11977                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11978                                         temp->backend.is_pinvoke = 1;
11979                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11980                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11981
11982                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11983                                         dest->type = STACK_VTYPE;
11984                                         dest->klass = klass;
11985
11986                                         *sp ++ = dest;
11987                                         ip += 6;
11988                                 }
11989                                 break;
11990                         case CEE_MONO_RETOBJ: {
11991                                 /*
11992                                  * Same as RET, but return the native representation of a vtype
11993                                  * to the caller.
11994                                  */
11995                                 g_assert (cfg->ret);
11996                                 g_assert (mono_method_signature (method)->pinvoke); 
11997                                 CHECK_STACK (1);
11998                                 --sp;
11999                                 
12000                                 CHECK_OPSIZE (6);
12001                                 token = read32 (ip + 2);    
12002                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12003
12004                                 if (!cfg->vret_addr) {
12005                                         g_assert (cfg->ret_var_is_local);
12006
12007                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12008                                 } else {
12009                                         EMIT_NEW_RETLOADA (cfg, ins);
12010                                 }
12011                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12012                                 
12013                                 if (sp != stack_start)
12014                                         UNVERIFIED;
12015                                 
12016                                 MONO_INST_NEW (cfg, ins, OP_BR);
12017                                 ins->inst_target_bb = end_bblock;
12018                                 MONO_ADD_INS (cfg->cbb, ins);
12019                                 link_bblock (cfg, cfg->cbb, end_bblock);
12020                                 start_new_bblock = 1;
12021                                 ip += 6;
12022                                 break;
12023                         }
12024                         case CEE_MONO_SAVE_LMF:
12025                         case CEE_MONO_RESTORE_LMF:
12026                                 ip += 2;
12027                                 break;
12028                         case CEE_MONO_CLASSCONST:
12029                                 CHECK_STACK_OVF (1);
12030                                 CHECK_OPSIZE (6);
12031                                 token = read32 (ip + 2);
12032                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12033                                 *sp++ = ins;
12034                                 ip += 6;
12035                                 inline_costs += 10 * num_calls++;
12036                                 break;
12037                         case CEE_MONO_NOT_TAKEN:
12038                                 cfg->cbb->out_of_line = TRUE;
12039                                 ip += 2;
12040                                 break;
12041                         case CEE_MONO_TLS: {
12042                                 MonoTlsKey key;
12043
12044                                 CHECK_STACK_OVF (1);
12045                                 CHECK_OPSIZE (6);
12046                                 key = (MonoTlsKey)read32 (ip + 2);
12047                                 g_assert (key < TLS_KEY_NUM);
12048
12049                                 ins = mono_create_tls_get (cfg, key);
12050                                 g_assert (ins);
12051                                 ins->type = STACK_PTR;
12052                                 *sp++ = ins;
12053                                 ip += 6;
12054                                 break;
12055                         }
12056                         case CEE_MONO_DYN_CALL: {
12057                                 MonoCallInst *call;
12058
12059                                 /* It would be easier to call a trampoline, but that would put an
12060                                  * extra frame on the stack, confusing exception handling. So
12061                                  * implement it inline using an opcode for now.
12062                                  */
12063
12064                                 if (!cfg->dyn_call_var) {
12065                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12066                                         /* prevent it from being register allocated */
12067                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12068                                 }
12069
12070                                 /* Has to use a call inst since it local regalloc expects it */
12071                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12072                                 ins = (MonoInst*)call;
12073                                 sp -= 2;
12074                                 ins->sreg1 = sp [0]->dreg;
12075                                 ins->sreg2 = sp [1]->dreg;
12076                                 MONO_ADD_INS (cfg->cbb, ins);
12077
12078                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12079
12080                                 ip += 2;
12081                                 inline_costs += 10 * num_calls++;
12082
12083                                 break;
12084                         }
12085                         case CEE_MONO_MEMORY_BARRIER: {
12086                                 CHECK_OPSIZE (6);
12087                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12088                                 ip += 6;
12089                                 break;
12090                         }
12091                         case CEE_MONO_ATOMIC_STORE_I4: {
12092                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
12093
12094                                 CHECK_OPSIZE (6);
12095                                 CHECK_STACK (2);
12096                                 sp -= 2;
12097
12098                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
12099                                 ins->dreg = sp [0]->dreg;
12100                                 ins->sreg1 = sp [1]->dreg;
12101                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
12102                                 MONO_ADD_INS (cfg->cbb, ins);
12103
12104                                 ip += 6;
12105                                 break;
12106                         }
12107                         case CEE_MONO_JIT_ATTACH: {
12108                                 MonoInst *args [16], *domain_ins;
12109                                 MonoInst *ad_ins, *jit_tls_ins;
12110                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12111
12112                                 g_assert (!mono_threads_is_coop_enabled ());
12113
12114                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12115
12116                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12117                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12118
12119                                 ad_ins = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
12120                                 jit_tls_ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
12121
12122                                 if (ad_ins && jit_tls_ins) {
12123                                         NEW_BBLOCK (cfg, next_bb);
12124                                         NEW_BBLOCK (cfg, call_bb);
12125
12126                                         if (cfg->compile_aot) {
12127                                                 /* AOT code is only used in the root domain */
12128                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12129                                         } else {
12130                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12131                                         }
12132                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12133                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12134
12135                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12136                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12137
12138                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12139                                         MONO_START_BB (cfg, call_bb);
12140                                 }
12141
12142                                 /* AOT code is only used in the root domain */
12143                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12144                                 if (cfg->compile_aot) {
12145                                         MonoInst *addr;
12146
12147                                         /*
12148                                          * This is called on unattached threads, so it cannot go through the trampoline
12149                                          * infrastructure. Use an indirect call through a got slot initialized at load time
12150                                          * instead.
12151                                          */
12152                                         EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_JIT_THREAD_ATTACH, NULL);
12153                                         ins = mono_emit_calli (cfg, helper_sig_jit_thread_attach, args, addr, NULL, NULL);
12154                                 } else {
12155                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12156                                 }
12157                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12158
12159                                 if (next_bb)
12160                                         MONO_START_BB (cfg, next_bb);
12161
12162                                 ip += 2;
12163                                 break;
12164                         }
12165                         case CEE_MONO_JIT_DETACH: {
12166                                 MonoInst *args [16];
12167
12168                                 /* Restore the original domain */
12169                                 dreg = alloc_ireg (cfg);
12170                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12171                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12172                                 ip += 2;
12173                                 break;
12174                         }
12175                         case CEE_MONO_CALLI_EXTRA_ARG: {
12176                                 MonoInst *addr;
12177                                 MonoMethodSignature *fsig;
12178                                 MonoInst *arg;
12179
12180                                 /*
12181                                  * This is the same as CEE_CALLI, but passes an additional argument
12182                                  * to the called method in llvmonly mode.
12183                                  * This is only used by delegate invoke wrappers to call the
12184                                  * actual delegate method.
12185                                  */
12186                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12187
12188                                 CHECK_OPSIZE (6);
12189                                 token = read32 (ip + 2);
12190
12191                                 ins = NULL;
12192
12193                                 cmethod = NULL;
12194                                 CHECK_STACK (1);
12195                                 --sp;
12196                                 addr = *sp;
12197                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12198                                 CHECK_CFG_ERROR;
12199
12200                                 if (cfg->llvm_only)
12201                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12202
12203                                 n = fsig->param_count + fsig->hasthis + 1;
12204
12205                                 CHECK_STACK (n);
12206
12207                                 sp -= n;
12208                                 arg = sp [n - 1];
12209
12210                                 if (cfg->llvm_only) {
12211                                         /*
12212                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12213                                          * cconv. This is set by mono_init_delegate ().
12214                                          */
12215                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12216                                                 MonoInst *callee = addr;
12217                                                 MonoInst *call, *localloc_ins;
12218                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12219                                                 int low_bit_reg = alloc_preg (cfg);
12220
12221                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12222                                                 NEW_BBLOCK (cfg, end_bb);
12223
12224                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12225                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12226                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12227
12228                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12229                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12230                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12231                                                 /*
12232                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12233                                                  */
12234                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12235                                                 ins->dreg = alloc_preg (cfg);
12236                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12237                                                 MONO_ADD_INS (cfg->cbb, ins);
12238                                                 localloc_ins = ins;
12239                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12240                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12241                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12242
12243                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12244                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12245
12246                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12247                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12248                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12249                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12250                                                 ins->dreg = call->dreg;
12251
12252                                                 MONO_START_BB (cfg, end_bb);
12253                                         } else {
12254                                                 /* Caller uses a normal calling conv */
12255
12256                                                 MonoInst *callee = addr;
12257                                                 MonoInst *call, *localloc_ins;
12258                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12259                                                 int low_bit_reg = alloc_preg (cfg);
12260
12261                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12262                                                 NEW_BBLOCK (cfg, end_bb);
12263
12264                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12265                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12266                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12267
12268                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12269                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12270                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12271                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12272                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12273                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12274                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12275                                                 MONO_ADD_INS (cfg->cbb, addr);
12276                                                 /*
12277                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12278                                                  */
12279                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12280                                                 ins->dreg = alloc_preg (cfg);
12281                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12282                                                 MONO_ADD_INS (cfg->cbb, ins);
12283                                                 localloc_ins = ins;
12284                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12285                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12286                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12287
12288                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12289                                                 ins->dreg = call->dreg;
12290                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12291
12292                                                 MONO_START_BB (cfg, end_bb);
12293                                         }
12294                                 } else {
12295                                         /* Same as CEE_CALLI */
12296                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12297                                                 /*
12298                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12299                                                  */
12300                                                 MonoInst *callee = addr;
12301
12302                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12303                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12304                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12305                                         } else {
12306                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12307                                         }
12308                                 }
12309
12310                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12311                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12312
12313                                 CHECK_CFG_EXCEPTION;
12314
12315                                 ip += 6;
12316                                 ins_flag = 0;
12317                                 constrained_class = NULL;
12318                                 break;
12319                         }
12320                         case CEE_MONO_LDDOMAIN:
12321                                 CHECK_STACK_OVF (1);
12322                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
12323                                 ip += 2;
12324                                 *sp++ = ins;
12325                                 break;
12326                         case CEE_MONO_GET_LAST_ERROR:
12327                                 CHECK_OPSIZE (2);
12328                                 CHECK_STACK_OVF (1);
12329
12330                                 MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
12331                                 ins->dreg = alloc_dreg (cfg, STACK_I4);
12332                                 ins->type = STACK_I4;
12333                                 MONO_ADD_INS (cfg->cbb, ins);
12334
12335                                 ip += 2;
12336                                 *sp++ = ins;
12337                                 break;
12338                         default:
12339                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12340                                 break;
12341                         }
12342                         break;
12343                 }
12344
12345                 case CEE_PREFIX1: {
12346                         CHECK_OPSIZE (2);
12347                         switch (ip [1]) {
12348                         case CEE_ARGLIST: {
12349                                 /* somewhat similar to LDTOKEN */
12350                                 MonoInst *addr, *vtvar;
12351                                 CHECK_STACK_OVF (1);
12352                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12353
12354                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12355                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12356
12357                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12358                                 ins->type = STACK_VTYPE;
12359                                 ins->klass = mono_defaults.argumenthandle_class;
12360                                 *sp++ = ins;
12361                                 ip += 2;
12362                                 break;
12363                         }
12364                         case CEE_CEQ:
12365                         case CEE_CGT:
12366                         case CEE_CGT_UN:
12367                         case CEE_CLT:
12368                         case CEE_CLT_UN: {
12369                                 MonoInst *cmp, *arg1, *arg2;
12370
12371                                 CHECK_STACK (2);
12372                                 sp -= 2;
12373                                 arg1 = sp [0];
12374                                 arg2 = sp [1];
12375
12376                                 /*
12377                                  * The following transforms:
12378                                  *    CEE_CEQ    into OP_CEQ
12379                                  *    CEE_CGT    into OP_CGT
12380                                  *    CEE_CGT_UN into OP_CGT_UN
12381                                  *    CEE_CLT    into OP_CLT
12382                                  *    CEE_CLT_UN into OP_CLT_UN
12383                                  */
12384                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12385
12386                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12387                                 cmp->sreg1 = arg1->dreg;
12388                                 cmp->sreg2 = arg2->dreg;
12389                                 type_from_op (cfg, cmp, arg1, arg2);
12390                                 CHECK_TYPE (cmp);
12391                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12392                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12393                                         cmp->opcode = OP_LCOMPARE;
12394                                 else if (arg1->type == STACK_R4)
12395                                         cmp->opcode = OP_RCOMPARE;
12396                                 else if (arg1->type == STACK_R8)
12397                                         cmp->opcode = OP_FCOMPARE;
12398                                 else
12399                                         cmp->opcode = OP_ICOMPARE;
12400                                 MONO_ADD_INS (cfg->cbb, cmp);
12401                                 ins->type = STACK_I4;
12402                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
12403                                 type_from_op (cfg, ins, arg1, arg2);
12404
12405                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12406                                         /*
12407                                          * The backends expect the fceq opcodes to do the
12408                                          * comparison too.
12409                                          */
12410                                         ins->sreg1 = cmp->sreg1;
12411                                         ins->sreg2 = cmp->sreg2;
12412                                         NULLIFY_INS (cmp);
12413                                 }
12414                                 MONO_ADD_INS (cfg->cbb, ins);
12415                                 *sp++ = ins;
12416                                 ip += 2;
12417                                 break;
12418                         }
12419                         case CEE_LDFTN: {
12420                                 MonoInst *argconst;
12421                                 MonoMethod *cil_method;
12422
12423                                 CHECK_STACK_OVF (1);
12424                                 CHECK_OPSIZE (6);
12425                                 n = read32 (ip + 2);
12426                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12427                                 CHECK_CFG_ERROR;
12428
12429                                 mono_class_init (cmethod->klass);
12430
12431                                 mono_save_token_info (cfg, image, n, cmethod);
12432
12433                                 context_used = mini_method_check_context_used (cfg, cmethod);
12434
12435                                 cil_method = cmethod;
12436                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12437                                         emit_method_access_failure (cfg, method, cil_method);
12438
12439                                 if (mono_security_core_clr_enabled ())
12440                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12441
12442                                 /* 
12443                                  * Optimize the common case of ldftn+delegate creation
12444                                  */
12445                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12446                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12447                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12448                                                 MonoInst *target_ins, *handle_ins;
12449                                                 MonoMethod *invoke;
12450                                                 int invoke_context_used;
12451
12452                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12453                                                 if (!invoke || !mono_method_signature (invoke))
12454                                                         LOAD_ERROR;
12455
12456                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12457
12458                                                 target_ins = sp [-1];
12459
12460                                                 if (mono_security_core_clr_enabled ())
12461                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12462
12463                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12464                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12465                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12466                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12467                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12468                                                         }
12469                                                 }
12470
12471                                                 /* FIXME: SGEN support */
12472                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12473                                                         ip += 6;
12474                                                         if (cfg->verbose_level > 3)
12475                                                                 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));
12476                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12477                                                                 sp --;
12478                                                                 *sp = handle_ins;
12479                                                                 CHECK_CFG_EXCEPTION;
12480                                                                 ip += 5;
12481                                                                 sp ++;
12482                                                                 break;
12483                                                         }
12484                                                         ip -= 6;
12485                                                 }
12486                                         }
12487                                 }
12488
12489                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12490                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12491                                 *sp++ = ins;
12492                                 
12493                                 ip += 6;
12494                                 inline_costs += 10 * num_calls++;
12495                                 break;
12496                         }
12497                         case CEE_LDVIRTFTN: {
12498                                 MonoInst *args [2];
12499
12500                                 CHECK_STACK (1);
12501                                 CHECK_OPSIZE (6);
12502                                 n = read32 (ip + 2);
12503                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12504                                 CHECK_CFG_ERROR;
12505
12506                                 mono_class_init (cmethod->klass);
12507  
12508                                 context_used = mini_method_check_context_used (cfg, cmethod);
12509
12510                                 if (mono_security_core_clr_enabled ())
12511                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12512
12513                                 /*
12514                                  * Optimize the common case of ldvirtftn+delegate creation
12515                                  */
12516                                 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)) {
12517                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12518                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12519                                                 MonoInst *target_ins, *handle_ins;
12520                                                 MonoMethod *invoke;
12521                                                 int invoke_context_used;
12522                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12523
12524                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12525                                                 if (!invoke || !mono_method_signature (invoke))
12526                                                         LOAD_ERROR;
12527
12528                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12529
12530                                                 target_ins = sp [-1];
12531
12532                                                 if (mono_security_core_clr_enabled ())
12533                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12534
12535                                                 /* FIXME: SGEN support */
12536                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12537                                                         ip += 6;
12538                                                         if (cfg->verbose_level > 3)
12539                                                                 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));
12540                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12541                                                                 sp -= 2;
12542                                                                 *sp = handle_ins;
12543                                                                 CHECK_CFG_EXCEPTION;
12544                                                                 ip += 5;
12545                                                                 sp ++;
12546                                                                 break;
12547                                                         }
12548                                                         ip -= 6;
12549                                                 }
12550                                         }
12551                                 }
12552
12553                                 --sp;
12554                                 args [0] = *sp;
12555
12556                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12557                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12558
12559                                 if (context_used)
12560                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12561                                 else
12562                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12563
12564                                 ip += 6;
12565                                 inline_costs += 10 * num_calls++;
12566                                 break;
12567                         }
12568                         case CEE_LDARG:
12569                                 CHECK_STACK_OVF (1);
12570                                 CHECK_OPSIZE (4);
12571                                 n = read16 (ip + 2);
12572                                 CHECK_ARG (n);
12573                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12574                                 *sp++ = ins;
12575                                 ip += 4;
12576                                 break;
12577                         case CEE_LDARGA:
12578                                 CHECK_STACK_OVF (1);
12579                                 CHECK_OPSIZE (4);
12580                                 n = read16 (ip + 2);
12581                                 CHECK_ARG (n);
12582                                 NEW_ARGLOADA (cfg, ins, n);
12583                                 MONO_ADD_INS (cfg->cbb, ins);
12584                                 *sp++ = ins;
12585                                 ip += 4;
12586                                 break;
12587                         case CEE_STARG:
12588                                 CHECK_STACK (1);
12589                                 --sp;
12590                                 CHECK_OPSIZE (4);
12591                                 n = read16 (ip + 2);
12592                                 CHECK_ARG (n);
12593                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12594                                         UNVERIFIED;
12595                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12596                                 ip += 4;
12597                                 break;
12598                         case CEE_LDLOC:
12599                                 CHECK_STACK_OVF (1);
12600                                 CHECK_OPSIZE (4);
12601                                 n = read16 (ip + 2);
12602                                 CHECK_LOCAL (n);
12603                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12604                                 *sp++ = ins;
12605                                 ip += 4;
12606                                 break;
12607                         case CEE_LDLOCA: {
12608                                 unsigned char *tmp_ip;
12609                                 CHECK_STACK_OVF (1);
12610                                 CHECK_OPSIZE (4);
12611                                 n = read16 (ip + 2);
12612                                 CHECK_LOCAL (n);
12613
12614                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12615                                         ip = tmp_ip;
12616                                         inline_costs += 1;
12617                                         break;
12618                                 }                       
12619                                 
12620                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12621                                 *sp++ = ins;
12622                                 ip += 4;
12623                                 break;
12624                         }
12625                         case CEE_STLOC:
12626                                 CHECK_STACK (1);
12627                                 --sp;
12628                                 CHECK_OPSIZE (4);
12629                                 n = read16 (ip + 2);
12630                                 CHECK_LOCAL (n);
12631                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12632                                         UNVERIFIED;
12633                                 emit_stloc_ir (cfg, sp, header, n);
12634                                 ip += 4;
12635                                 inline_costs += 1;
12636                                 break;
12637                         case CEE_LOCALLOC: {
12638                                 CHECK_STACK (1);
12639                                 MonoBasicBlock *non_zero_bb, *end_bb;
12640                                 int alloc_ptr = alloc_preg (cfg);
12641                                 --sp;
12642                                 if (sp != stack_start) 
12643                                         UNVERIFIED;
12644                                 if (cfg->method != method) 
12645                                         /* 
12646                                          * Inlining this into a loop in a parent could lead to 
12647                                          * stack overflows which is different behavior than the
12648                                          * non-inlined case, thus disable inlining in this case.
12649                                          */
12650                                         INLINE_FAILURE("localloc");
12651
12652                                 NEW_BBLOCK (cfg, non_zero_bb);
12653                                 NEW_BBLOCK (cfg, end_bb);
12654
12655                                 /* if size != zero */
12656                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
12657                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
12658
12659                                 //size is zero, so result is NULL
12660                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
12661                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12662
12663                                 MONO_START_BB (cfg, non_zero_bb);
12664                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12665                                 ins->dreg = alloc_ptr;
12666                                 ins->sreg1 = sp [0]->dreg;
12667                                 ins->type = STACK_PTR;
12668                                 MONO_ADD_INS (cfg->cbb, ins);
12669
12670                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12671                                 if (init_locals)
12672                                         ins->flags |= MONO_INST_INIT;
12673
12674                                 MONO_START_BB (cfg, end_bb);
12675                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
12676                                 ins->type = STACK_PTR;
12677
12678                                 *sp++ = ins;
12679                                 ip += 2;
12680                                 break;
12681                         }
12682                         case CEE_ENDFILTER: {
12683                                 MonoExceptionClause *clause, *nearest;
12684                                 int cc;
12685
12686                                 CHECK_STACK (1);
12687                                 --sp;
12688                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12689                                         UNVERIFIED;
12690                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12691                                 ins->sreg1 = (*sp)->dreg;
12692                                 MONO_ADD_INS (cfg->cbb, ins);
12693                                 start_new_bblock = 1;
12694                                 ip += 2;
12695
12696                                 nearest = NULL;
12697                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12698                                         clause = &header->clauses [cc];
12699                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12700                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12701                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12702                                                 nearest = clause;
12703                                 }
12704                                 g_assert (nearest);
12705                                 if ((ip - header->code) != nearest->handler_offset)
12706                                         UNVERIFIED;
12707
12708                                 break;
12709                         }
12710                         case CEE_UNALIGNED_:
12711                                 ins_flag |= MONO_INST_UNALIGNED;
12712                                 /* FIXME: record alignment? we can assume 1 for now */
12713                                 CHECK_OPSIZE (3);
12714                                 ip += 3;
12715                                 break;
12716                         case CEE_VOLATILE_:
12717                                 ins_flag |= MONO_INST_VOLATILE;
12718                                 ip += 2;
12719                                 break;
12720                         case CEE_TAIL_:
12721                                 ins_flag   |= MONO_INST_TAILCALL;
12722                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12723                                 /* Can't inline tail calls at this time */
12724                                 inline_costs += 100000;
12725                                 ip += 2;
12726                                 break;
12727                         case CEE_INITOBJ:
12728                                 CHECK_STACK (1);
12729                                 --sp;
12730                                 CHECK_OPSIZE (6);
12731                                 token = read32 (ip + 2);
12732                                 klass = mini_get_class (method, token, generic_context);
12733                                 CHECK_TYPELOAD (klass);
12734                                 if (generic_class_is_reference_type (cfg, klass))
12735                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12736                                 else
12737                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12738                                 ip += 6;
12739                                 inline_costs += 1;
12740                                 break;
12741                         case CEE_CONSTRAINED_:
12742                                 CHECK_OPSIZE (6);
12743                                 token = read32 (ip + 2);
12744                                 constrained_class = mini_get_class (method, token, generic_context);
12745                                 CHECK_TYPELOAD (constrained_class);
12746                                 ip += 6;
12747                                 break;
12748                         case CEE_CPBLK:
12749                         case CEE_INITBLK: {
12750                                 MonoInst *iargs [3];
12751                                 CHECK_STACK (3);
12752                                 sp -= 3;
12753
12754                                 /* Skip optimized paths for volatile operations. */
12755                                 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)) {
12756                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12757                                 } 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)) {
12758                                         /* emit_memset only works when val == 0 */
12759                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12760                                 } else {
12761                                         MonoInst *call;
12762                                         iargs [0] = sp [0];
12763                                         iargs [1] = sp [1];
12764                                         iargs [2] = sp [2];
12765                                         if (ip [1] == CEE_CPBLK) {
12766                                                 /*
12767                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12768                                                  * and release barriers for cpblk. It is technically both a load and
12769                                                  * store operation, so it seems like that's the sensible thing to do.
12770                                                  *
12771                                                  * FIXME: We emit full barriers on both sides of the operation for
12772                                                  * simplicity. We should have a separate atomic memcpy method instead.
12773                                                  */
12774                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12775
12776                                                 if (ins_flag & MONO_INST_VOLATILE)
12777                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12778
12779                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12780                                                 call->flags |= ins_flag;
12781
12782                                                 if (ins_flag & MONO_INST_VOLATILE)
12783                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12784                                         } else {
12785                                                 MonoMethod *memset_method = get_memset_method ();
12786                                                 if (ins_flag & MONO_INST_VOLATILE) {
12787                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12788                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12789                                                 }
12790                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12791                                                 call->flags |= ins_flag;
12792                                         }
12793                                 }
12794                                 ip += 2;
12795                                 ins_flag = 0;
12796                                 inline_costs += 1;
12797                                 break;
12798                         }
12799                         case CEE_NO_:
12800                                 CHECK_OPSIZE (3);
12801                                 if (ip [2] & 0x1)
12802                                         ins_flag |= MONO_INST_NOTYPECHECK;
12803                                 if (ip [2] & 0x2)
12804                                         ins_flag |= MONO_INST_NORANGECHECK;
12805                                 /* we ignore the no-nullcheck for now since we
12806                                  * really do it explicitly only when doing callvirt->call
12807                                  */
12808                                 ip += 3;
12809                                 break;
12810                         case CEE_RETHROW: {
12811                                 MonoInst *load;
12812                                 int handler_offset = -1;
12813
12814                                 for (i = 0; i < header->num_clauses; ++i) {
12815                                         MonoExceptionClause *clause = &header->clauses [i];
12816                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12817                                                 handler_offset = clause->handler_offset;
12818                                                 break;
12819                                         }
12820                                 }
12821
12822                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12823
12824                                 if (handler_offset == -1)
12825                                         UNVERIFIED;
12826
12827                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12828                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12829                                 ins->sreg1 = load->dreg;
12830                                 MONO_ADD_INS (cfg->cbb, ins);
12831
12832                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12833                                 MONO_ADD_INS (cfg->cbb, ins);
12834
12835                                 sp = stack_start;
12836                                 link_bblock (cfg, cfg->cbb, end_bblock);
12837                                 start_new_bblock = 1;
12838                                 ip += 2;
12839                                 break;
12840                         }
12841                         case CEE_SIZEOF: {
12842                                 guint32 val;
12843                                 int ialign;
12844
12845                                 CHECK_STACK_OVF (1);
12846                                 CHECK_OPSIZE (6);
12847                                 token = read32 (ip + 2);
12848                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12849                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12850                                         CHECK_CFG_ERROR;
12851
12852                                         val = mono_type_size (type, &ialign);
12853                                 } else {
12854                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12855                                         CHECK_TYPELOAD (klass);
12856
12857                                         val = mono_type_size (&klass->byval_arg, &ialign);
12858
12859                                         if (mini_is_gsharedvt_klass (klass))
12860                                                 GSHAREDVT_FAILURE (*ip);
12861                                 }
12862                                 EMIT_NEW_ICONST (cfg, ins, val);
12863                                 *sp++= ins;
12864                                 ip += 6;
12865                                 break;
12866                         }
12867                         case CEE_REFANYTYPE: {
12868                                 MonoInst *src_var, *src;
12869
12870                                 GSHAREDVT_FAILURE (*ip);
12871
12872                                 CHECK_STACK (1);
12873                                 --sp;
12874
12875                                 // FIXME:
12876                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12877                                 if (!src_var)
12878                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12879                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12880                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12881                                 *sp++ = ins;
12882                                 ip += 2;
12883                                 break;
12884                         }
12885                         case CEE_READONLY_:
12886                                 readonly = TRUE;
12887                                 ip += 2;
12888                                 break;
12889
12890                         case CEE_UNUSED56:
12891                         case CEE_UNUSED57:
12892                         case CEE_UNUSED70:
12893                         case CEE_UNUSED:
12894                         case CEE_UNUSED99:
12895                                 UNVERIFIED;
12896                                 
12897                         default:
12898                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12899                                 UNVERIFIED;
12900                         }
12901                         break;
12902                 }
12903                 case CEE_UNUSED58:
12904                 case CEE_UNUSED1:
12905                         UNVERIFIED;
12906
12907                 default:
12908                         g_warning ("opcode 0x%02x not handled", *ip);
12909                         UNVERIFIED;
12910                 }
12911         }
12912         if (start_new_bblock != 1)
12913                 UNVERIFIED;
12914
12915         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
12916         if (cfg->cbb->next_bb) {
12917                 /* This could already be set because of inlining, #693905 */
12918                 MonoBasicBlock *bb = cfg->cbb;
12919
12920                 while (bb->next_bb)
12921                         bb = bb->next_bb;
12922                 bb->next_bb = end_bblock;
12923         } else {
12924                 cfg->cbb->next_bb = end_bblock;
12925         }
12926
12927         if (cfg->method == method && cfg->domainvar) {
12928                 MonoInst *store;
12929                 MonoInst *get_domain;
12930
12931                 cfg->cbb = init_localsbb;
12932
12933                 get_domain = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
12934                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12935                 MONO_ADD_INS (cfg->cbb, store);
12936         }
12937
12938 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12939         if (cfg->compile_aot)
12940                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12941                 mono_get_got_var (cfg);
12942 #endif
12943
12944         if (cfg->method == method && cfg->got_var)
12945                 mono_emit_load_got_addr (cfg);
12946
12947         if (init_localsbb) {
12948                 cfg->cbb = init_localsbb;
12949                 cfg->ip = NULL;
12950                 for (i = 0; i < header->num_locals; ++i) {
12951                         emit_init_local (cfg, i, header->locals [i], init_locals);
12952                 }
12953         }
12954
12955         if (cfg->init_ref_vars && cfg->method == method) {
12956                 /* Emit initialization for ref vars */
12957                 // FIXME: Avoid duplication initialization for IL locals.
12958                 for (i = 0; i < cfg->num_varinfo; ++i) {
12959                         MonoInst *ins = cfg->varinfo [i];
12960
12961                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12962                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12963                 }
12964         }
12965
12966         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
12967                 cfg->cbb = init_localsbb;
12968                 emit_push_lmf (cfg);
12969         }
12970
12971         cfg->cbb = init_localsbb;
12972         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12973
12974         if (seq_points) {
12975                 MonoBasicBlock *bb;
12976
12977                 /*
12978                  * Make seq points at backward branch targets interruptable.
12979                  */
12980                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12981                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12982                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12983         }
12984
12985         /* Add a sequence point for method entry/exit events */
12986         if (seq_points && cfg->gen_sdb_seq_points) {
12987                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12988                 MONO_ADD_INS (init_localsbb, ins);
12989                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12990                 MONO_ADD_INS (cfg->bb_exit, ins);
12991         }
12992
12993         /*
12994          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12995          * the code they refer to was dead (#11880).
12996          */
12997         if (sym_seq_points) {
12998                 for (i = 0; i < header->code_size; ++i) {
12999                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13000                                 MonoInst *ins;
13001
13002                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13003                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13004                         }
13005                 }
13006         }
13007
13008         cfg->ip = NULL;
13009
13010         if (cfg->method == method) {
13011                 MonoBasicBlock *bb;
13012                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13013                         if (bb == cfg->bb_init)
13014                                 bb->region = -1;
13015                         else
13016                                 bb->region = mono_find_block_region (cfg, bb->real_offset);
13017                         if (cfg->spvars)
13018                                 mono_create_spvar_for_region (cfg, bb->region);
13019                         if (cfg->verbose_level > 2)
13020                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13021                 }
13022         } else {
13023                 MonoBasicBlock *bb;
13024                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
13025                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
13026                         bb->real_offset = inline_offset;
13027                 }
13028         }
13029
13030         if (inline_costs < 0) {
13031                 char *mname;
13032
13033                 /* Method is too large */
13034                 mname = mono_method_full_name (method, TRUE);
13035                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13036                 g_free (mname);
13037         }
13038
13039         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13040                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13041
13042         goto cleanup;
13043
13044 mono_error_exit:
13045         g_assert (!mono_error_ok (&cfg->error));
13046         goto cleanup;
13047  
13048  exception_exit:
13049         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13050         goto cleanup;
13051
13052  unverified:
13053         set_exception_type_from_invalid_il (cfg, method, ip);
13054         goto cleanup;
13055
13056  cleanup:
13057         g_slist_free (class_inits);
13058         mono_basic_block_free (original_bb);
13059         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13060         if (cfg->exception_type)
13061                 return -1;
13062         else
13063                 return inline_costs;
13064 }
13065
13066 static int
13067 store_membase_reg_to_store_membase_imm (int opcode)
13068 {
13069         switch (opcode) {
13070         case OP_STORE_MEMBASE_REG:
13071                 return OP_STORE_MEMBASE_IMM;
13072         case OP_STOREI1_MEMBASE_REG:
13073                 return OP_STOREI1_MEMBASE_IMM;
13074         case OP_STOREI2_MEMBASE_REG:
13075                 return OP_STOREI2_MEMBASE_IMM;
13076         case OP_STOREI4_MEMBASE_REG:
13077                 return OP_STOREI4_MEMBASE_IMM;
13078         case OP_STOREI8_MEMBASE_REG:
13079                 return OP_STOREI8_MEMBASE_IMM;
13080         default:
13081                 g_assert_not_reached ();
13082         }
13083
13084         return -1;
13085 }               
13086
13087 int
13088 mono_op_to_op_imm (int opcode)
13089 {
13090         switch (opcode) {
13091         case OP_IADD:
13092                 return OP_IADD_IMM;
13093         case OP_ISUB:
13094                 return OP_ISUB_IMM;
13095         case OP_IDIV:
13096                 return OP_IDIV_IMM;
13097         case OP_IDIV_UN:
13098                 return OP_IDIV_UN_IMM;
13099         case OP_IREM:
13100                 return OP_IREM_IMM;
13101         case OP_IREM_UN:
13102                 return OP_IREM_UN_IMM;
13103         case OP_IMUL:
13104                 return OP_IMUL_IMM;
13105         case OP_IAND:
13106                 return OP_IAND_IMM;
13107         case OP_IOR:
13108                 return OP_IOR_IMM;
13109         case OP_IXOR:
13110                 return OP_IXOR_IMM;
13111         case OP_ISHL:
13112                 return OP_ISHL_IMM;
13113         case OP_ISHR:
13114                 return OP_ISHR_IMM;
13115         case OP_ISHR_UN:
13116                 return OP_ISHR_UN_IMM;
13117
13118         case OP_LADD:
13119                 return OP_LADD_IMM;
13120         case OP_LSUB:
13121                 return OP_LSUB_IMM;
13122         case OP_LAND:
13123                 return OP_LAND_IMM;
13124         case OP_LOR:
13125                 return OP_LOR_IMM;
13126         case OP_LXOR:
13127                 return OP_LXOR_IMM;
13128         case OP_LSHL:
13129                 return OP_LSHL_IMM;
13130         case OP_LSHR:
13131                 return OP_LSHR_IMM;
13132         case OP_LSHR_UN:
13133                 return OP_LSHR_UN_IMM;
13134 #if SIZEOF_REGISTER == 8
13135         case OP_LREM:
13136                 return OP_LREM_IMM;
13137 #endif
13138
13139         case OP_COMPARE:
13140                 return OP_COMPARE_IMM;
13141         case OP_ICOMPARE:
13142                 return OP_ICOMPARE_IMM;
13143         case OP_LCOMPARE:
13144                 return OP_LCOMPARE_IMM;
13145
13146         case OP_STORE_MEMBASE_REG:
13147                 return OP_STORE_MEMBASE_IMM;
13148         case OP_STOREI1_MEMBASE_REG:
13149                 return OP_STOREI1_MEMBASE_IMM;
13150         case OP_STOREI2_MEMBASE_REG:
13151                 return OP_STOREI2_MEMBASE_IMM;
13152         case OP_STOREI4_MEMBASE_REG:
13153                 return OP_STOREI4_MEMBASE_IMM;
13154
13155 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13156         case OP_X86_PUSH:
13157                 return OP_X86_PUSH_IMM;
13158         case OP_X86_COMPARE_MEMBASE_REG:
13159                 return OP_X86_COMPARE_MEMBASE_IMM;
13160 #endif
13161 #if defined(TARGET_AMD64)
13162         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13163                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13164 #endif
13165         case OP_VOIDCALL_REG:
13166                 return OP_VOIDCALL;
13167         case OP_CALL_REG:
13168                 return OP_CALL;
13169         case OP_LCALL_REG:
13170                 return OP_LCALL;
13171         case OP_FCALL_REG:
13172                 return OP_FCALL;
13173         case OP_LOCALLOC:
13174                 return OP_LOCALLOC_IMM;
13175         }
13176
13177         return -1;
13178 }
13179
13180 static int
13181 ldind_to_load_membase (int opcode)
13182 {
13183         switch (opcode) {
13184         case CEE_LDIND_I1:
13185                 return OP_LOADI1_MEMBASE;
13186         case CEE_LDIND_U1:
13187                 return OP_LOADU1_MEMBASE;
13188         case CEE_LDIND_I2:
13189                 return OP_LOADI2_MEMBASE;
13190         case CEE_LDIND_U2:
13191                 return OP_LOADU2_MEMBASE;
13192         case CEE_LDIND_I4:
13193                 return OP_LOADI4_MEMBASE;
13194         case CEE_LDIND_U4:
13195                 return OP_LOADU4_MEMBASE;
13196         case CEE_LDIND_I:
13197                 return OP_LOAD_MEMBASE;
13198         case CEE_LDIND_REF:
13199                 return OP_LOAD_MEMBASE;
13200         case CEE_LDIND_I8:
13201                 return OP_LOADI8_MEMBASE;
13202         case CEE_LDIND_R4:
13203                 return OP_LOADR4_MEMBASE;
13204         case CEE_LDIND_R8:
13205                 return OP_LOADR8_MEMBASE;
13206         default:
13207                 g_assert_not_reached ();
13208         }
13209
13210         return -1;
13211 }
13212
13213 static int
13214 stind_to_store_membase (int opcode)
13215 {
13216         switch (opcode) {
13217         case CEE_STIND_I1:
13218                 return OP_STOREI1_MEMBASE_REG;
13219         case CEE_STIND_I2:
13220                 return OP_STOREI2_MEMBASE_REG;
13221         case CEE_STIND_I4:
13222                 return OP_STOREI4_MEMBASE_REG;
13223         case CEE_STIND_I:
13224         case CEE_STIND_REF:
13225                 return OP_STORE_MEMBASE_REG;
13226         case CEE_STIND_I8:
13227                 return OP_STOREI8_MEMBASE_REG;
13228         case CEE_STIND_R4:
13229                 return OP_STORER4_MEMBASE_REG;
13230         case CEE_STIND_R8:
13231                 return OP_STORER8_MEMBASE_REG;
13232         default:
13233                 g_assert_not_reached ();
13234         }
13235
13236         return -1;
13237 }
13238
13239 int
13240 mono_load_membase_to_load_mem (int opcode)
13241 {
13242         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13243 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13244         switch (opcode) {
13245         case OP_LOAD_MEMBASE:
13246                 return OP_LOAD_MEM;
13247         case OP_LOADU1_MEMBASE:
13248                 return OP_LOADU1_MEM;
13249         case OP_LOADU2_MEMBASE:
13250                 return OP_LOADU2_MEM;
13251         case OP_LOADI4_MEMBASE:
13252                 return OP_LOADI4_MEM;
13253         case OP_LOADU4_MEMBASE:
13254                 return OP_LOADU4_MEM;
13255 #if SIZEOF_REGISTER == 8
13256         case OP_LOADI8_MEMBASE:
13257                 return OP_LOADI8_MEM;
13258 #endif
13259         }
13260 #endif
13261
13262         return -1;
13263 }
13264
13265 static inline int
13266 op_to_op_dest_membase (int store_opcode, int opcode)
13267 {
13268 #if defined(TARGET_X86)
13269         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13270                 return -1;
13271
13272         switch (opcode) {
13273         case OP_IADD:
13274                 return OP_X86_ADD_MEMBASE_REG;
13275         case OP_ISUB:
13276                 return OP_X86_SUB_MEMBASE_REG;
13277         case OP_IAND:
13278                 return OP_X86_AND_MEMBASE_REG;
13279         case OP_IOR:
13280                 return OP_X86_OR_MEMBASE_REG;
13281         case OP_IXOR:
13282                 return OP_X86_XOR_MEMBASE_REG;
13283         case OP_ADD_IMM:
13284         case OP_IADD_IMM:
13285                 return OP_X86_ADD_MEMBASE_IMM;
13286         case OP_SUB_IMM:
13287         case OP_ISUB_IMM:
13288                 return OP_X86_SUB_MEMBASE_IMM;
13289         case OP_AND_IMM:
13290         case OP_IAND_IMM:
13291                 return OP_X86_AND_MEMBASE_IMM;
13292         case OP_OR_IMM:
13293         case OP_IOR_IMM:
13294                 return OP_X86_OR_MEMBASE_IMM;
13295         case OP_XOR_IMM:
13296         case OP_IXOR_IMM:
13297                 return OP_X86_XOR_MEMBASE_IMM;
13298         case OP_MOVE:
13299                 return OP_NOP;
13300         }
13301 #endif
13302
13303 #if defined(TARGET_AMD64)
13304         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13305                 return -1;
13306
13307         switch (opcode) {
13308         case OP_IADD:
13309                 return OP_X86_ADD_MEMBASE_REG;
13310         case OP_ISUB:
13311                 return OP_X86_SUB_MEMBASE_REG;
13312         case OP_IAND:
13313                 return OP_X86_AND_MEMBASE_REG;
13314         case OP_IOR:
13315                 return OP_X86_OR_MEMBASE_REG;
13316         case OP_IXOR:
13317                 return OP_X86_XOR_MEMBASE_REG;
13318         case OP_IADD_IMM:
13319                 return OP_X86_ADD_MEMBASE_IMM;
13320         case OP_ISUB_IMM:
13321                 return OP_X86_SUB_MEMBASE_IMM;
13322         case OP_IAND_IMM:
13323                 return OP_X86_AND_MEMBASE_IMM;
13324         case OP_IOR_IMM:
13325                 return OP_X86_OR_MEMBASE_IMM;
13326         case OP_IXOR_IMM:
13327                 return OP_X86_XOR_MEMBASE_IMM;
13328         case OP_LADD:
13329                 return OP_AMD64_ADD_MEMBASE_REG;
13330         case OP_LSUB:
13331                 return OP_AMD64_SUB_MEMBASE_REG;
13332         case OP_LAND:
13333                 return OP_AMD64_AND_MEMBASE_REG;
13334         case OP_LOR:
13335                 return OP_AMD64_OR_MEMBASE_REG;
13336         case OP_LXOR:
13337                 return OP_AMD64_XOR_MEMBASE_REG;
13338         case OP_ADD_IMM:
13339         case OP_LADD_IMM:
13340                 return OP_AMD64_ADD_MEMBASE_IMM;
13341         case OP_SUB_IMM:
13342         case OP_LSUB_IMM:
13343                 return OP_AMD64_SUB_MEMBASE_IMM;
13344         case OP_AND_IMM:
13345         case OP_LAND_IMM:
13346                 return OP_AMD64_AND_MEMBASE_IMM;
13347         case OP_OR_IMM:
13348         case OP_LOR_IMM:
13349                 return OP_AMD64_OR_MEMBASE_IMM;
13350         case OP_XOR_IMM:
13351         case OP_LXOR_IMM:
13352                 return OP_AMD64_XOR_MEMBASE_IMM;
13353         case OP_MOVE:
13354                 return OP_NOP;
13355         }
13356 #endif
13357
13358         return -1;
13359 }
13360
13361 static inline int
13362 op_to_op_store_membase (int store_opcode, int opcode)
13363 {
13364 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13365         switch (opcode) {
13366         case OP_ICEQ:
13367                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13368                         return OP_X86_SETEQ_MEMBASE;
13369         case OP_CNE:
13370                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13371                         return OP_X86_SETNE_MEMBASE;
13372         }
13373 #endif
13374
13375         return -1;
13376 }
13377
13378 static inline int
13379 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13380 {
13381 #ifdef TARGET_X86
13382         /* FIXME: This has sign extension issues */
13383         /*
13384         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13385                 return OP_X86_COMPARE_MEMBASE8_IMM;
13386         */
13387
13388         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13389                 return -1;
13390
13391         switch (opcode) {
13392         case OP_X86_PUSH:
13393                 return OP_X86_PUSH_MEMBASE;
13394         case OP_COMPARE_IMM:
13395         case OP_ICOMPARE_IMM:
13396                 return OP_X86_COMPARE_MEMBASE_IMM;
13397         case OP_COMPARE:
13398         case OP_ICOMPARE:
13399                 return OP_X86_COMPARE_MEMBASE_REG;
13400         }
13401 #endif
13402
13403 #ifdef TARGET_AMD64
13404         /* FIXME: This has sign extension issues */
13405         /*
13406         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13407                 return OP_X86_COMPARE_MEMBASE8_IMM;
13408         */
13409
13410         switch (opcode) {
13411         case OP_X86_PUSH:
13412                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13413                         return OP_X86_PUSH_MEMBASE;
13414                 break;
13415                 /* FIXME: This only works for 32 bit immediates
13416         case OP_COMPARE_IMM:
13417         case OP_LCOMPARE_IMM:
13418                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13419                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13420                 */
13421         case OP_ICOMPARE_IMM:
13422                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13423                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13424                 break;
13425         case OP_COMPARE:
13426         case OP_LCOMPARE:
13427                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
13428                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13429                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13430                         return OP_AMD64_COMPARE_MEMBASE_REG;
13431                 break;
13432         case OP_ICOMPARE:
13433                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13434                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13435                 break;
13436         }
13437 #endif
13438
13439         return -1;
13440 }
13441
13442 static inline int
13443 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
13444 {
13445 #ifdef TARGET_X86
13446         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13447                 return -1;
13448         
13449         switch (opcode) {
13450         case OP_COMPARE:
13451         case OP_ICOMPARE:
13452                 return OP_X86_COMPARE_REG_MEMBASE;
13453         case OP_IADD:
13454                 return OP_X86_ADD_REG_MEMBASE;
13455         case OP_ISUB:
13456                 return OP_X86_SUB_REG_MEMBASE;
13457         case OP_IAND:
13458                 return OP_X86_AND_REG_MEMBASE;
13459         case OP_IOR:
13460                 return OP_X86_OR_REG_MEMBASE;
13461         case OP_IXOR:
13462                 return OP_X86_XOR_REG_MEMBASE;
13463         }
13464 #endif
13465
13466 #ifdef TARGET_AMD64
13467         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
13468                 switch (opcode) {
13469                 case OP_ICOMPARE:
13470                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13471                 case OP_IADD:
13472                         return OP_X86_ADD_REG_MEMBASE;
13473                 case OP_ISUB:
13474                         return OP_X86_SUB_REG_MEMBASE;
13475                 case OP_IAND:
13476                         return OP_X86_AND_REG_MEMBASE;
13477                 case OP_IOR:
13478                         return OP_X86_OR_REG_MEMBASE;
13479                 case OP_IXOR:
13480                         return OP_X86_XOR_REG_MEMBASE;
13481                 }
13482         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
13483                 switch (opcode) {
13484                 case OP_COMPARE:
13485                 case OP_LCOMPARE:
13486                         return OP_AMD64_COMPARE_REG_MEMBASE;
13487                 case OP_LADD:
13488                         return OP_AMD64_ADD_REG_MEMBASE;
13489                 case OP_LSUB:
13490                         return OP_AMD64_SUB_REG_MEMBASE;
13491                 case OP_LAND:
13492                         return OP_AMD64_AND_REG_MEMBASE;
13493                 case OP_LOR:
13494                         return OP_AMD64_OR_REG_MEMBASE;
13495                 case OP_LXOR:
13496                         return OP_AMD64_XOR_REG_MEMBASE;
13497                 }
13498         }
13499 #endif
13500
13501         return -1;
13502 }
13503
13504 int
13505 mono_op_to_op_imm_noemul (int opcode)
13506 {
13507         switch (opcode) {
13508 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13509         case OP_LSHR:
13510         case OP_LSHL:
13511         case OP_LSHR_UN:
13512                 return -1;
13513 #endif
13514 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13515         case OP_IDIV:
13516         case OP_IDIV_UN:
13517         case OP_IREM:
13518         case OP_IREM_UN:
13519                 return -1;
13520 #endif
13521 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13522         case OP_IMUL:
13523                 return -1;
13524 #endif
13525         default:
13526                 return mono_op_to_op_imm (opcode);
13527         }
13528 }
13529
13530 /**
13531  * mono_handle_global_vregs:
13532  *
13533  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13534  * for them.
13535  */
13536 void
13537 mono_handle_global_vregs (MonoCompile *cfg)
13538 {
13539         gint32 *vreg_to_bb;
13540         MonoBasicBlock *bb;
13541         int i, pos;
13542
13543         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13544
13545 #ifdef MONO_ARCH_SIMD_INTRINSICS
13546         if (cfg->uses_simd_intrinsics)
13547                 mono_simd_simplify_indirection (cfg);
13548 #endif
13549
13550         /* Find local vregs used in more than one bb */
13551         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13552                 MonoInst *ins = bb->code;       
13553                 int block_num = bb->block_num;
13554
13555                 if (cfg->verbose_level > 2)
13556                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13557
13558                 cfg->cbb = bb;
13559                 for (; ins; ins = ins->next) {
13560                         const char *spec = INS_INFO (ins->opcode);
13561                         int regtype = 0, regindex;
13562                         gint32 prev_bb;
13563
13564                         if (G_UNLIKELY (cfg->verbose_level > 2))
13565                                 mono_print_ins (ins);
13566
13567                         g_assert (ins->opcode >= MONO_CEE_LAST);
13568
13569                         for (regindex = 0; regindex < 4; regindex ++) {
13570                                 int vreg = 0;
13571
13572                                 if (regindex == 0) {
13573                                         regtype = spec [MONO_INST_DEST];
13574                                         if (regtype == ' ')
13575                                                 continue;
13576                                         vreg = ins->dreg;
13577                                 } else if (regindex == 1) {
13578                                         regtype = spec [MONO_INST_SRC1];
13579                                         if (regtype == ' ')
13580                                                 continue;
13581                                         vreg = ins->sreg1;
13582                                 } else if (regindex == 2) {
13583                                         regtype = spec [MONO_INST_SRC2];
13584                                         if (regtype == ' ')
13585                                                 continue;
13586                                         vreg = ins->sreg2;
13587                                 } else if (regindex == 3) {
13588                                         regtype = spec [MONO_INST_SRC3];
13589                                         if (regtype == ' ')
13590                                                 continue;
13591                                         vreg = ins->sreg3;
13592                                 }
13593
13594 #if SIZEOF_REGISTER == 4
13595                                 /* In the LLVM case, the long opcodes are not decomposed */
13596                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13597                                         /*
13598                                          * Since some instructions reference the original long vreg,
13599                                          * and some reference the two component vregs, it is quite hard
13600                                          * to determine when it needs to be global. So be conservative.
13601                                          */
13602                                         if (!get_vreg_to_inst (cfg, vreg)) {
13603                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13604
13605                                                 if (cfg->verbose_level > 2)
13606                                                         printf ("LONG VREG R%d made global.\n", vreg);
13607                                         }
13608
13609                                         /*
13610                                          * Make the component vregs volatile since the optimizations can
13611                                          * get confused otherwise.
13612                                          */
13613                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
13614                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
13615                                 }
13616 #endif
13617
13618                                 g_assert (vreg != -1);
13619
13620                                 prev_bb = vreg_to_bb [vreg];
13621                                 if (prev_bb == 0) {
13622                                         /* 0 is a valid block num */
13623                                         vreg_to_bb [vreg] = block_num + 1;
13624                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13625                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13626                                                 continue;
13627
13628                                         if (!get_vreg_to_inst (cfg, vreg)) {
13629                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13630                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13631
13632                                                 switch (regtype) {
13633                                                 case 'i':
13634                                                         if (vreg_is_ref (cfg, vreg))
13635                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13636                                                         else
13637                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13638                                                         break;
13639                                                 case 'l':
13640                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13641                                                         break;
13642                                                 case 'f':
13643                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13644                                                         break;
13645                                                 case 'v':
13646                                                 case 'x':
13647                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13648                                                         break;
13649                                                 default:
13650                                                         g_assert_not_reached ();
13651                                                 }
13652                                         }
13653
13654                                         /* Flag as having been used in more than one bb */
13655                                         vreg_to_bb [vreg] = -1;
13656                                 }
13657                         }
13658                 }
13659         }
13660
13661         /* If a variable is used in only one bblock, convert it into a local vreg */
13662         for (i = 0; i < cfg->num_varinfo; i++) {
13663                 MonoInst *var = cfg->varinfo [i];
13664                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13665
13666                 switch (var->type) {
13667                 case STACK_I4:
13668                 case STACK_OBJ:
13669                 case STACK_PTR:
13670                 case STACK_MP:
13671                 case STACK_VTYPE:
13672 #if SIZEOF_REGISTER == 8
13673                 case STACK_I8:
13674 #endif
13675 #if !defined(TARGET_X86)
13676                 /* Enabling this screws up the fp stack on x86 */
13677                 case STACK_R8:
13678 #endif
13679                         if (mono_arch_is_soft_float ())
13680                                 break;
13681
13682                         /*
13683                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
13684                                 break;
13685                         */
13686
13687                         /* Arguments are implicitly global */
13688                         /* Putting R4 vars into registers doesn't work currently */
13689                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13690                         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) {
13691                                 /* 
13692                                  * Make that the variable's liveness interval doesn't contain a call, since
13693                                  * that would cause the lvreg to be spilled, making the whole optimization
13694                                  * useless.
13695                                  */
13696                                 /* This is too slow for JIT compilation */
13697 #if 0
13698                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13699                                         MonoInst *ins;
13700                                         int def_index, call_index, ins_index;
13701                                         gboolean spilled = FALSE;
13702
13703                                         def_index = -1;
13704                                         call_index = -1;
13705                                         ins_index = 0;
13706                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13707                                                 const char *spec = INS_INFO (ins->opcode);
13708
13709                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13710                                                         def_index = ins_index;
13711
13712                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13713                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13714                                                         if (call_index > def_index) {
13715                                                                 spilled = TRUE;
13716                                                                 break;
13717                                                         }
13718                                                 }
13719
13720                                                 if (MONO_IS_CALL (ins))
13721                                                         call_index = ins_index;
13722
13723                                                 ins_index ++;
13724                                         }
13725
13726                                         if (spilled)
13727                                                 break;
13728                                 }
13729 #endif
13730
13731                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13732                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13733                                 var->flags |= MONO_INST_IS_DEAD;
13734                                 cfg->vreg_to_inst [var->dreg] = NULL;
13735                         }
13736                         break;
13737                 }
13738         }
13739
13740         /* 
13741          * Compress the varinfo and vars tables so the liveness computation is faster and
13742          * takes up less space.
13743          */
13744         pos = 0;
13745         for (i = 0; i < cfg->num_varinfo; ++i) {
13746                 MonoInst *var = cfg->varinfo [i];
13747                 if (pos < i && cfg->locals_start == i)
13748                         cfg->locals_start = pos;
13749                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13750                         if (pos < i) {
13751                                 cfg->varinfo [pos] = cfg->varinfo [i];
13752                                 cfg->varinfo [pos]->inst_c0 = pos;
13753                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13754                                 cfg->vars [pos].idx = pos;
13755 #if SIZEOF_REGISTER == 4
13756                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13757                                         /* Modify the two component vars too */
13758                                         MonoInst *var1;
13759
13760                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
13761                                         var1->inst_c0 = pos;
13762                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
13763                                         var1->inst_c0 = pos;
13764                                 }
13765 #endif
13766                         }
13767                         pos ++;
13768                 }
13769         }
13770         cfg->num_varinfo = pos;
13771         if (cfg->locals_start > cfg->num_varinfo)
13772                 cfg->locals_start = cfg->num_varinfo;
13773 }
13774
13775 /*
13776  * mono_allocate_gsharedvt_vars:
13777  *
13778  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
13779  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
13780  */
13781 void
13782 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
13783 {
13784         int i;
13785
13786         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13787
13788         for (i = 0; i < cfg->num_varinfo; ++i) {
13789                 MonoInst *ins = cfg->varinfo [i];
13790                 int idx;
13791
13792                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13793                         if (i >= cfg->locals_start) {
13794                                 /* Local */
13795                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13796                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13797                                 ins->opcode = OP_GSHAREDVT_LOCAL;
13798                                 ins->inst_imm = idx;
13799                         } else {
13800                                 /* Arg */
13801                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
13802                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13803                         }
13804                 }
13805         }
13806 }
13807
13808 /**
13809  * mono_spill_global_vars:
13810  *
13811  *   Generate spill code for variables which are not allocated to registers, 
13812  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13813  * code is generated which could be optimized by the local optimization passes.
13814  */
13815 void
13816 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13817 {
13818         MonoBasicBlock *bb;
13819         char spec2 [16];
13820         int orig_next_vreg;
13821         guint32 *vreg_to_lvreg;
13822         guint32 *lvregs;
13823         guint32 i, lvregs_len, lvregs_size;
13824         gboolean dest_has_lvreg = FALSE;
13825         MonoStackType stacktypes [128];
13826         MonoInst **live_range_start, **live_range_end;
13827         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13828
13829         *need_local_opts = FALSE;
13830
13831         memset (spec2, 0, sizeof (spec2));
13832
13833         /* FIXME: Move this function to mini.c */
13834         stacktypes ['i'] = STACK_PTR;
13835         stacktypes ['l'] = STACK_I8;
13836         stacktypes ['f'] = STACK_R8;
13837 #ifdef MONO_ARCH_SIMD_INTRINSICS
13838         stacktypes ['x'] = STACK_VTYPE;
13839 #endif
13840
13841 #if SIZEOF_REGISTER == 4
13842         /* Create MonoInsts for longs */
13843         for (i = 0; i < cfg->num_varinfo; i++) {
13844                 MonoInst *ins = cfg->varinfo [i];
13845
13846                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13847                         switch (ins->type) {
13848                         case STACK_R8:
13849                         case STACK_I8: {
13850                                 MonoInst *tree;
13851
13852                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13853                                         break;
13854
13855                                 g_assert (ins->opcode == OP_REGOFFSET);
13856
13857                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
13858                                 g_assert (tree);
13859                                 tree->opcode = OP_REGOFFSET;
13860                                 tree->inst_basereg = ins->inst_basereg;
13861                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13862
13863                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
13864                                 g_assert (tree);
13865                                 tree->opcode = OP_REGOFFSET;
13866                                 tree->inst_basereg = ins->inst_basereg;
13867                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13868                                 break;
13869                         }
13870                         default:
13871                                 break;
13872                         }
13873                 }
13874         }
13875 #endif
13876
13877         if (cfg->compute_gc_maps) {
13878                 /* registers need liveness info even for !non refs */
13879                 for (i = 0; i < cfg->num_varinfo; i++) {
13880                         MonoInst *ins = cfg->varinfo [i];
13881
13882                         if (ins->opcode == OP_REGVAR)
13883                                 ins->flags |= MONO_INST_GC_TRACK;
13884                 }
13885         }
13886                 
13887         /* FIXME: widening and truncation */
13888
13889         /*
13890          * As an optimization, when a variable allocated to the stack is first loaded into 
13891          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13892          * the variable again.
13893          */
13894         orig_next_vreg = cfg->next_vreg;
13895         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13896         lvregs_size = 1024;
13897         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * lvregs_size);
13898         lvregs_len = 0;
13899
13900         /* 
13901          * These arrays contain the first and last instructions accessing a given
13902          * variable.
13903          * Since we emit bblocks in the same order we process them here, and we
13904          * don't split live ranges, these will precisely describe the live range of
13905          * the variable, i.e. the instruction range where a valid value can be found
13906          * in the variables location.
13907          * The live range is computed using the liveness info computed by the liveness pass.
13908          * We can't use vmv->range, since that is an abstract live range, and we need
13909          * one which is instruction precise.
13910          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13911          */
13912         /* FIXME: Only do this if debugging info is requested */
13913         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13914         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13915         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13916         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13917         
13918         /* Add spill loads/stores */
13919         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13920                 MonoInst *ins;
13921
13922                 if (cfg->verbose_level > 2)
13923                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13924
13925                 /* Clear vreg_to_lvreg array */
13926                 for (i = 0; i < lvregs_len; i++)
13927                         vreg_to_lvreg [lvregs [i]] = 0;
13928                 lvregs_len = 0;
13929
13930                 cfg->cbb = bb;
13931                 MONO_BB_FOR_EACH_INS (bb, ins) {
13932                         const char *spec = INS_INFO (ins->opcode);
13933                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13934                         gboolean store, no_lvreg;
13935                         int sregs [MONO_MAX_SRC_REGS];
13936
13937                         if (G_UNLIKELY (cfg->verbose_level > 2))
13938                                 mono_print_ins (ins);
13939
13940                         if (ins->opcode == OP_NOP)
13941                                 continue;
13942
13943                         /* 
13944                          * We handle LDADDR here as well, since it can only be decomposed
13945                          * when variable addresses are known.
13946                          */
13947                         if (ins->opcode == OP_LDADDR) {
13948                                 MonoInst *var = (MonoInst *)ins->inst_p0;
13949
13950                                 if (var->opcode == OP_VTARG_ADDR) {
13951                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13952                                         MonoInst *vtaddr = var->inst_left;
13953                                         if (vtaddr->opcode == OP_REGVAR) {
13954                                                 ins->opcode = OP_MOVE;
13955                                                 ins->sreg1 = vtaddr->dreg;
13956                                         }
13957                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13958                                                 ins->opcode = OP_LOAD_MEMBASE;
13959                                                 ins->inst_basereg = vtaddr->inst_basereg;
13960                                                 ins->inst_offset = vtaddr->inst_offset;
13961                                         } else
13962                                                 NOT_IMPLEMENTED;
13963                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
13964                                         /* gsharedvt arg passed by ref */
13965                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13966
13967                                         ins->opcode = OP_LOAD_MEMBASE;
13968                                         ins->inst_basereg = var->inst_basereg;
13969                                         ins->inst_offset = var->inst_offset;
13970                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
13971                                         MonoInst *load, *load2, *load3;
13972                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
13973                                         int reg1, reg2, reg3;
13974                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13975                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13976
13977                                         /*
13978                                          * gsharedvt local.
13979                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13980                                          */
13981
13982                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13983
13984                                         g_assert (info_var);
13985                                         g_assert (locals_var);
13986
13987                                         /* Mark the instruction used to compute the locals var as used */
13988                                         cfg->gsharedvt_locals_var_ins = NULL;
13989
13990                                         /* Load the offset */
13991                                         if (info_var->opcode == OP_REGOFFSET) {
13992                                                 reg1 = alloc_ireg (cfg);
13993                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13994                                         } else if (info_var->opcode == OP_REGVAR) {
13995                                                 load = NULL;
13996                                                 reg1 = info_var->dreg;
13997                                         } else {
13998                                                 g_assert_not_reached ();
13999                                         }
14000                                         reg2 = alloc_ireg (cfg);
14001                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14002                                         /* Load the locals area address */
14003                                         reg3 = alloc_ireg (cfg);
14004                                         if (locals_var->opcode == OP_REGOFFSET) {
14005                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14006                                         } else if (locals_var->opcode == OP_REGVAR) {
14007                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14008                                         } else {
14009                                                 g_assert_not_reached ();
14010                                         }
14011                                         /* Compute the address */
14012                                         ins->opcode = OP_PADD;
14013                                         ins->sreg1 = reg3;
14014                                         ins->sreg2 = reg2;
14015
14016                                         mono_bblock_insert_before_ins (bb, ins, load3);
14017                                         mono_bblock_insert_before_ins (bb, load3, load2);
14018                                         if (load)
14019                                                 mono_bblock_insert_before_ins (bb, load2, load);
14020                                 } else {
14021                                         g_assert (var->opcode == OP_REGOFFSET);
14022
14023                                         ins->opcode = OP_ADD_IMM;
14024                                         ins->sreg1 = var->inst_basereg;
14025                                         ins->inst_imm = var->inst_offset;
14026                                 }
14027
14028                                 *need_local_opts = TRUE;
14029                                 spec = INS_INFO (ins->opcode);
14030                         }
14031
14032                         if (ins->opcode < MONO_CEE_LAST) {
14033                                 mono_print_ins (ins);
14034                                 g_assert_not_reached ();
14035                         }
14036
14037                         /*
14038                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14039                          * src register.
14040                          * FIXME:
14041                          */
14042                         if (MONO_IS_STORE_MEMBASE (ins)) {
14043                                 tmp_reg = ins->dreg;
14044                                 ins->dreg = ins->sreg2;
14045                                 ins->sreg2 = tmp_reg;
14046                                 store = TRUE;
14047
14048                                 spec2 [MONO_INST_DEST] = ' ';
14049                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14050                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14051                                 spec2 [MONO_INST_SRC3] = ' ';
14052                                 spec = spec2;
14053                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14054                                 g_assert_not_reached ();
14055                         else
14056                                 store = FALSE;
14057                         no_lvreg = FALSE;
14058
14059                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14060                                 printf ("\t %.3s %d", spec, ins->dreg);
14061                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14062                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14063                                         printf (" %d", sregs [srcindex]);
14064                                 printf ("\n");
14065                         }
14066
14067                         /***************/
14068                         /*    DREG     */
14069                         /***************/
14070                         regtype = spec [MONO_INST_DEST];
14071                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14072                         prev_dreg = -1;
14073
14074                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14075                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14076                                 MonoInst *store_ins;
14077                                 int store_opcode;
14078                                 MonoInst *def_ins = ins;
14079                                 int dreg = ins->dreg; /* The original vreg */
14080
14081                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14082
14083                                 if (var->opcode == OP_REGVAR) {
14084                                         ins->dreg = var->dreg;
14085                                 } 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)) {
14086                                         /* 
14087                                          * Instead of emitting a load+store, use a _membase opcode.
14088                                          */
14089                                         g_assert (var->opcode == OP_REGOFFSET);
14090                                         if (ins->opcode == OP_MOVE) {
14091                                                 NULLIFY_INS (ins);
14092                                                 def_ins = NULL;
14093                                         } else {
14094                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14095                                                 ins->inst_basereg = var->inst_basereg;
14096                                                 ins->inst_offset = var->inst_offset;
14097                                                 ins->dreg = -1;
14098                                         }
14099                                         spec = INS_INFO (ins->opcode);
14100                                 } else {
14101                                         guint32 lvreg;
14102
14103                                         g_assert (var->opcode == OP_REGOFFSET);
14104
14105                                         prev_dreg = ins->dreg;
14106
14107                                         /* Invalidate any previous lvreg for this vreg */
14108                                         vreg_to_lvreg [ins->dreg] = 0;
14109
14110                                         lvreg = 0;
14111
14112                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14113                                                 regtype = 'l';
14114                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14115                                         }
14116
14117                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14118
14119 #if SIZEOF_REGISTER != 8
14120                                         if (regtype == 'l') {
14121                                                 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));
14122                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14123                                                 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));
14124                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14125                                                 def_ins = store_ins;
14126                                         }
14127                                         else
14128 #endif
14129                                         {
14130                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14131
14132                                                 /* Try to fuse the store into the instruction itself */
14133                                                 /* FIXME: Add more instructions */
14134                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14135                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14136                                                         ins->inst_imm = ins->inst_c0;
14137                                                         ins->inst_destbasereg = var->inst_basereg;
14138                                                         ins->inst_offset = var->inst_offset;
14139                                                         spec = INS_INFO (ins->opcode);
14140                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14141                                                         ins->opcode = store_opcode;
14142                                                         ins->inst_destbasereg = var->inst_basereg;
14143                                                         ins->inst_offset = var->inst_offset;
14144
14145                                                         no_lvreg = TRUE;
14146
14147                                                         tmp_reg = ins->dreg;
14148                                                         ins->dreg = ins->sreg2;
14149                                                         ins->sreg2 = tmp_reg;
14150                                                         store = TRUE;
14151
14152                                                         spec2 [MONO_INST_DEST] = ' ';
14153                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14154                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14155                                                         spec2 [MONO_INST_SRC3] = ' ';
14156                                                         spec = spec2;
14157                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14158                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14159                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14160                                                         ins->dreg = -1;
14161                                                         ins->inst_basereg = var->inst_basereg;
14162                                                         ins->inst_offset = var->inst_offset;
14163                                                         spec = INS_INFO (ins->opcode);
14164                                                 } else {
14165                                                         /* printf ("INS: "); mono_print_ins (ins); */
14166                                                         /* Create a store instruction */
14167                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14168
14169                                                         /* Insert it after the instruction */
14170                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14171
14172                                                         def_ins = store_ins;
14173
14174                                                         /* 
14175                                                          * We can't assign ins->dreg to var->dreg here, since the
14176                                                          * sregs could use it. So set a flag, and do it after
14177                                                          * the sregs.
14178                                                          */
14179                                                         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)))
14180                                                                 dest_has_lvreg = TRUE;
14181                                                 }
14182                                         }
14183                                 }
14184
14185                                 if (def_ins && !live_range_start [dreg]) {
14186                                         live_range_start [dreg] = def_ins;
14187                                         live_range_start_bb [dreg] = bb;
14188                                 }
14189
14190                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14191                                         MonoInst *tmp;
14192
14193                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14194                                         tmp->inst_c1 = dreg;
14195                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14196                                 }
14197                         }
14198
14199                         /************/
14200                         /*  SREGS   */
14201                         /************/
14202                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14203                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14204                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14205                                 sreg = sregs [srcindex];
14206
14207                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14208                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14209                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14210                                         MonoInst *use_ins = ins;
14211                                         MonoInst *load_ins;
14212                                         guint32 load_opcode;
14213
14214                                         if (var->opcode == OP_REGVAR) {
14215                                                 sregs [srcindex] = var->dreg;
14216                                                 //mono_inst_set_src_registers (ins, sregs);
14217                                                 live_range_end [sreg] = use_ins;
14218                                                 live_range_end_bb [sreg] = bb;
14219
14220                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14221                                                         MonoInst *tmp;
14222
14223                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14224                                                         /* var->dreg is a hreg */
14225                                                         tmp->inst_c1 = sreg;
14226                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14227                                                 }
14228
14229                                                 continue;
14230                                         }
14231
14232                                         g_assert (var->opcode == OP_REGOFFSET);
14233                                                 
14234                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14235
14236                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14237
14238                                         if (vreg_to_lvreg [sreg]) {
14239                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14240
14241                                                 /* The variable is already loaded to an lvreg */
14242                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14243                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14244                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14245                                                 //mono_inst_set_src_registers (ins, sregs);
14246                                                 continue;
14247                                         }
14248
14249                                         /* Try to fuse the load into the instruction */
14250                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14251                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14252                                                 sregs [0] = var->inst_basereg;
14253                                                 //mono_inst_set_src_registers (ins, sregs);
14254                                                 ins->inst_offset = var->inst_offset;
14255                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14256                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14257                                                 sregs [1] = var->inst_basereg;
14258                                                 //mono_inst_set_src_registers (ins, sregs);
14259                                                 ins->inst_offset = var->inst_offset;
14260                                         } else {
14261                                                 if (MONO_IS_REAL_MOVE (ins)) {
14262                                                         ins->opcode = OP_NOP;
14263                                                         sreg = ins->dreg;
14264                                                 } else {
14265                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14266
14267                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14268
14269                                                         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) {
14270                                                                 if (var->dreg == prev_dreg) {
14271                                                                         /*
14272                                                                          * sreg refers to the value loaded by the load
14273                                                                          * emitted below, but we need to use ins->dreg
14274                                                                          * since it refers to the store emitted earlier.
14275                                                                          */
14276                                                                         sreg = ins->dreg;
14277                                                                 }
14278                                                                 g_assert (sreg != -1);
14279                                                                 vreg_to_lvreg [var->dreg] = sreg;
14280                                                                 if (lvregs_len >= lvregs_size) {
14281                                                                         guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
14282                                                                         memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
14283                                                                         lvregs = new_lvregs;
14284                                                                         lvregs_size *= 2;
14285                                                                 }
14286                                                                 lvregs [lvregs_len ++] = var->dreg;
14287                                                         }
14288                                                 }
14289
14290                                                 sregs [srcindex] = sreg;
14291                                                 //mono_inst_set_src_registers (ins, sregs);
14292
14293 #if SIZEOF_REGISTER != 8
14294                                                 if (regtype == 'l') {
14295                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14296                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14297                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14298                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14299                                                         use_ins = load_ins;
14300                                                 }
14301                                                 else
14302 #endif
14303                                                 {
14304 #if SIZEOF_REGISTER == 4
14305                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14306 #endif
14307                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14308                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14309                                                         use_ins = load_ins;
14310                                                 }
14311                                         }
14312
14313                                         if (var->dreg < orig_next_vreg) {
14314                                                 live_range_end [var->dreg] = use_ins;
14315                                                 live_range_end_bb [var->dreg] = bb;
14316                                         }
14317
14318                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14319                                                 MonoInst *tmp;
14320
14321                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14322                                                 tmp->inst_c1 = var->dreg;
14323                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14324                                         }
14325                                 }
14326                         }
14327                         mono_inst_set_src_registers (ins, sregs);
14328
14329                         if (dest_has_lvreg) {
14330                                 g_assert (ins->dreg != -1);
14331                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14332                                 if (lvregs_len >= lvregs_size) {
14333                                         guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
14334                                         memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
14335                                         lvregs = new_lvregs;
14336                                         lvregs_size *= 2;
14337                                 }
14338                                 lvregs [lvregs_len ++] = prev_dreg;
14339                                 dest_has_lvreg = FALSE;
14340                         }
14341
14342                         if (store) {
14343                                 tmp_reg = ins->dreg;
14344                                 ins->dreg = ins->sreg2;
14345                                 ins->sreg2 = tmp_reg;
14346                         }
14347
14348                         if (MONO_IS_CALL (ins)) {
14349                                 /* Clear vreg_to_lvreg array */
14350                                 for (i = 0; i < lvregs_len; i++)
14351                                         vreg_to_lvreg [lvregs [i]] = 0;
14352                                 lvregs_len = 0;
14353                         } else if (ins->opcode == OP_NOP) {
14354                                 ins->dreg = -1;
14355                                 MONO_INST_NULLIFY_SREGS (ins);
14356                         }
14357
14358                         if (cfg->verbose_level > 2)
14359                                 mono_print_ins_index (1, ins);
14360                 }
14361
14362                 /* Extend the live range based on the liveness info */
14363                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14364                         for (i = 0; i < cfg->num_varinfo; i ++) {
14365                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14366
14367                                 if (vreg_is_volatile (cfg, vi->vreg))
14368                                         /* The liveness info is incomplete */
14369                                         continue;
14370
14371                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14372                                         /* Live from at least the first ins of this bb */
14373                                         live_range_start [vi->vreg] = bb->code;
14374                                         live_range_start_bb [vi->vreg] = bb;
14375                                 }
14376
14377                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14378                                         /* Live at least until the last ins of this bb */
14379                                         live_range_end [vi->vreg] = bb->last_ins;
14380                                         live_range_end_bb [vi->vreg] = bb;
14381                                 }
14382                         }
14383                 }
14384         }
14385         
14386         /*
14387          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14388          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14389          */
14390         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14391                 for (i = 0; i < cfg->num_varinfo; ++i) {
14392                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14393                         MonoInst *ins;
14394
14395                         if (live_range_start [vreg]) {
14396                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14397                                 ins->inst_c0 = i;
14398                                 ins->inst_c1 = vreg;
14399                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14400                         }
14401                         if (live_range_end [vreg]) {
14402                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14403                                 ins->inst_c0 = i;
14404                                 ins->inst_c1 = vreg;
14405                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14406                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14407                                 else
14408                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14409                         }
14410                 }
14411         }
14412
14413         if (cfg->gsharedvt_locals_var_ins) {
14414                 /* Nullify if unused */
14415                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14416                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14417         }
14418
14419         g_free (live_range_start);
14420         g_free (live_range_end);
14421         g_free (live_range_start_bb);
14422         g_free (live_range_end_bb);
14423 }
14424
14425
14426 /**
14427  * FIXME:
14428  * - use 'iadd' instead of 'int_add'
14429  * - handling ovf opcodes: decompose in method_to_ir.
14430  * - unify iregs/fregs
14431  *   -> partly done, the missing parts are:
14432  *   - a more complete unification would involve unifying the hregs as well, so
14433  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14434  *     would no longer map to the machine hregs, so the code generators would need to
14435  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14436  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14437  *     fp/non-fp branches speeds it up by about 15%.
14438  * - use sext/zext opcodes instead of shifts
14439  * - add OP_ICALL
14440  * - get rid of TEMPLOADs if possible and use vregs instead
14441  * - clean up usage of OP_P/OP_ opcodes
14442  * - cleanup usage of DUMMY_USE
14443  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14444  *   stack
14445  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14446  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14447  * - make sure handle_stack_args () is called before the branch is emitted
14448  * - when the new IR is done, get rid of all unused stuff
14449  * - COMPARE/BEQ as separate instructions or unify them ?
14450  *   - keeping them separate allows specialized compare instructions like
14451  *     compare_imm, compare_membase
14452  *   - most back ends unify fp compare+branch, fp compare+ceq
14453  * - integrate mono_save_args into inline_method
14454  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14455  * - handle long shift opts on 32 bit platforms somehow: they require 
14456  *   3 sregs (2 for arg1 and 1 for arg2)
14457  * - make byref a 'normal' type.
14458  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14459  *   variable if needed.
14460  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14461  *   like inline_method.
14462  * - remove inlining restrictions
14463  * - fix LNEG and enable cfold of INEG
14464  * - generalize x86 optimizations like ldelema as a peephole optimization
14465  * - add store_mem_imm for amd64
14466  * - optimize the loading of the interruption flag in the managed->native wrappers
14467  * - avoid special handling of OP_NOP in passes
14468  * - move code inserting instructions into one function/macro.
14469  * - try a coalescing phase after liveness analysis
14470  * - add float -> vreg conversion + local optimizations on !x86
14471  * - figure out how to handle decomposed branches during optimizations, ie.
14472  *   compare+branch, op_jump_table+op_br etc.
14473  * - promote RuntimeXHandles to vregs
14474  * - vtype cleanups:
14475  *   - add a NEW_VARLOADA_VREG macro
14476  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14477  *   accessing vtype fields.
14478  * - get rid of I8CONST on 64 bit platforms
14479  * - dealing with the increase in code size due to branches created during opcode
14480  *   decomposition:
14481  *   - use extended basic blocks
14482  *     - all parts of the JIT
14483  *     - handle_global_vregs () && local regalloc
14484  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14485  * - sources of increase in code size:
14486  *   - vtypes
14487  *   - long compares
14488  *   - isinst and castclass
14489  *   - lvregs not allocated to global registers even if used multiple times
14490  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14491  *   meaningful.
14492  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14493  * - add all micro optimizations from the old JIT
14494  * - put tree optimizations into the deadce pass
14495  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14496  *   specific function.
14497  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14498  *   fcompare + branchCC.
14499  * - create a helper function for allocating a stack slot, taking into account 
14500  *   MONO_CFG_HAS_SPILLUP.
14501  * - merge r68207.
14502  * - merge the ia64 switch changes.
14503  * - optimize mono_regstate2_alloc_int/float.
14504  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14505  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14506  *   parts of the tree could be separated by other instructions, killing the tree
14507  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14508  *   instructions if the result of the load is used multiple times ?
14509  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14510  * - LAST MERGE: 108395.
14511  * - when returning vtypes in registers, generate IR and append it to the end of the
14512  *   last bb instead of doing it in the epilog.
14513  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14514  */
14515
14516 /*
14517
14518 NOTES
14519 -----
14520
14521 - When to decompose opcodes:
14522   - earlier: this makes some optimizations hard to implement, since the low level IR
14523   no longer contains the neccessary information. But it is easier to do.
14524   - later: harder to implement, enables more optimizations.
14525 - Branches inside bblocks:
14526   - created when decomposing complex opcodes. 
14527     - branches to another bblock: harmless, but not tracked by the branch 
14528       optimizations, so need to branch to a label at the start of the bblock.
14529     - branches to inside the same bblock: very problematic, trips up the local
14530       reg allocator. Can be fixed by spitting the current bblock, but that is a
14531       complex operation, since some local vregs can become global vregs etc.
14532 - Local/global vregs:
14533   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14534     local register allocator.
14535   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14536     structure, created by mono_create_var (). Assigned to hregs or the stack by
14537     the global register allocator.
14538 - When to do optimizations like alu->alu_imm:
14539   - earlier -> saves work later on since the IR will be smaller/simpler
14540   - later -> can work on more instructions
14541 - Handling of valuetypes:
14542   - When a vtype is pushed on the stack, a new temporary is created, an 
14543     instruction computing its address (LDADDR) is emitted and pushed on
14544     the stack. Need to optimize cases when the vtype is used immediately as in
14545     argument passing, stloc etc.
14546 - Instead of the to_end stuff in the old JIT, simply call the function handling
14547   the values on the stack before emitting the last instruction of the bb.
14548 */
14549
14550 #else /* !DISABLE_JIT */
14551
14552 MONO_EMPTY_SOURCE_FILE (method_to_ir);
14553
14554 #endif /* !DISABLE_JIT */