Merge pull request #4444 from lateralusX/jlorenss/windows-unwind-info
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12  */
13
14 #include <config.h>
15 #include <mono/utils/mono-compiler.h>
16 #include "mini.h"
17
18 #ifndef DISABLE_JIT
19
20 #include <signal.h>
21
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25
26 #include <math.h>
27 #include <string.h>
28 #include <ctype.h>
29
30 #ifdef HAVE_SYS_TIME_H
31 #include <sys/time.h>
32 #endif
33
34 #ifdef HAVE_ALLOCA_H
35 #include <alloca.h>
36 #endif
37
38 #include <mono/utils/memcheck.h>
39 #include <mono/metadata/abi-details.h>
40 #include <mono/metadata/assembly.h>
41 #include <mono/metadata/attrdefs.h>
42 #include <mono/metadata/loader.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/class.h>
45 #include <mono/metadata/object.h>
46 #include <mono/metadata/exception.h>
47 #include <mono/metadata/opcodes.h>
48 #include <mono/metadata/mono-endian.h>
49 #include <mono/metadata/tokentype.h>
50 #include <mono/metadata/tabledefs.h>
51 #include <mono/metadata/marshal.h>
52 #include <mono/metadata/debug-helpers.h>
53 #include <mono/metadata/debug-internals.h>
54 #include <mono/metadata/gc-internals.h>
55 #include <mono/metadata/security-manager.h>
56 #include <mono/metadata/threads-types.h>
57 #include <mono/metadata/security-core-clr.h>
58 #include <mono/metadata/profiler-private.h>
59 #include <mono/metadata/profiler.h>
60 #include <mono/metadata/monitor.h>
61 #include <mono/utils/mono-memory-model.h>
62 #include <mono/utils/mono-error-internals.h>
63 #include <mono/metadata/mono-basic-block.h>
64 #include <mono/metadata/reflection-internals.h>
65 #include <mono/utils/mono-threads-coop.h>
66
67 #include "trace.h"
68
69 #include "ir-emit.h"
70
71 #include "jit-icalls.h"
72 #include "jit.h"
73 #include "debugger-agent.h"
74 #include "seq-points.h"
75 #include "aot-compiler.h"
76 #include "mini-llvm.h"
77
78 #define BRANCH_COST 10
79 #define INLINE_LENGTH_LIMIT 20
80
81 /* These have 'cfg' as an implicit argument */
82 #define INLINE_FAILURE(msg) do {                                                                        \
83         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
84                 inline_failure (cfg, msg);                                                                              \
85                 goto exception_exit;                                                                                    \
86         } \
87         } while (0)
88 #define CHECK_CFG_EXCEPTION do {\
89                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
90                         goto exception_exit;                                            \
91         } while (0)
92 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
93                 field_access_failure ((cfg), (method), (field));                        \
94                 goto exception_exit;    \
95         } while (0)
96 #define GENERIC_SHARING_FAILURE(opcode) do {            \
97                 if (cfg->gshared) {                                                                     \
98                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
99                         goto exception_exit;    \
100                 }                       \
101         } while (0)
102 #define GSHAREDVT_FAILURE(opcode) do {          \
103         if (cfg->gsharedvt) {                                                                                           \
104                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
105                 goto exception_exit;                                                                                    \
106         }                                                                                                                                       \
107         } while (0)
108 #define OUT_OF_MEMORY_FAILURE do {      \
109                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
110                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
111                 goto exception_exit;    \
112         } while (0)
113 #define DISABLE_AOT(cfg) do { \
114                 if ((cfg)->verbose_level >= 2)                                            \
115                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
116                 (cfg)->disable_aot = TRUE;                                                        \
117         } while (0)
118 #define LOAD_ERROR do { \
119                 break_on_unverified ();                                                         \
120                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
121                 goto exception_exit;                                                                    \
122         } while (0)
123
124 #define TYPE_LOAD_ERROR(klass) do { \
125                 cfg->exception_ptr = klass; \
126                 LOAD_ERROR;                                     \
127         } while (0)
128
129 #define CHECK_CFG_ERROR do {\
130                 if (!mono_error_ok (&cfg->error)) { \
131                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
132                         goto mono_error_exit; \
133                 } \
134         } while (0)
135
136 /* Determine whenever 'ins' represents a load of the 'this' argument */
137 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
138
139 static int ldind_to_load_membase (int opcode);
140 static int stind_to_store_membase (int opcode);
141
142 int mono_op_to_op_imm (int opcode);
143 int mono_op_to_op_imm_noemul (int opcode);
144
145 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
146                                                   guchar *ip, guint real_offset, gboolean inline_always);
147 static MonoInst*
148 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
149
150 inline static MonoInst*
151 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg);
152
153 /* helper methods signatures */
154 static MonoMethodSignature *helper_sig_domain_get;
155 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
156 static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline;
157 static MonoMethodSignature *helper_sig_jit_thread_attach;
158 static MonoMethodSignature *helper_sig_get_tls_tramp;
159 static MonoMethodSignature *helper_sig_set_tls_tramp;
160
161 /* type loading helpers */
162 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, "System.Runtime.CompilerServices", "RuntimeHelpers")
163 static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, "System.Diagnostics", "DebuggableAttribute")
164
165 /*
166  * Instruction metadata
167  */
168 #ifdef MINI_OP
169 #undef MINI_OP
170 #endif
171 #ifdef MINI_OP3
172 #undef MINI_OP3
173 #endif
174 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
175 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
176 #define NONE ' '
177 #define IREG 'i'
178 #define FREG 'f'
179 #define VREG 'v'
180 #define XREG 'x'
181 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
182 #define LREG IREG
183 #else
184 #define LREG 'l'
185 #endif
186 /* keep in sync with the enum in mini.h */
187 const char
188 ins_info[] = {
189 #include "mini-ops.h"
190 };
191 #undef MINI_OP
192 #undef MINI_OP3
193
194 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
195 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
196 /* 
197  * This should contain the index of the last sreg + 1. This is not the same
198  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
199  */
200 const gint8 ins_sreg_counts[] = {
201 #include "mini-ops.h"
202 };
203 #undef MINI_OP
204 #undef MINI_OP3
205
206 guint32
207 mono_alloc_ireg (MonoCompile *cfg)
208 {
209         return alloc_ireg (cfg);
210 }
211
212 guint32
213 mono_alloc_lreg (MonoCompile *cfg)
214 {
215         return alloc_lreg (cfg);
216 }
217
218 guint32
219 mono_alloc_freg (MonoCompile *cfg)
220 {
221         return alloc_freg (cfg);
222 }
223
224 guint32
225 mono_alloc_preg (MonoCompile *cfg)
226 {
227         return alloc_preg (cfg);
228 }
229
230 guint32
231 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
232 {
233         return alloc_dreg (cfg, stack_type);
234 }
235
236 /*
237  * mono_alloc_ireg_ref:
238  *
239  *   Allocate an IREG, and mark it as holding a GC ref.
240  */
241 guint32
242 mono_alloc_ireg_ref (MonoCompile *cfg)
243 {
244         return alloc_ireg_ref (cfg);
245 }
246
247 /*
248  * mono_alloc_ireg_mp:
249  *
250  *   Allocate an IREG, and mark it as holding a managed pointer.
251  */
252 guint32
253 mono_alloc_ireg_mp (MonoCompile *cfg)
254 {
255         return alloc_ireg_mp (cfg);
256 }
257
258 /*
259  * mono_alloc_ireg_copy:
260  *
261  *   Allocate an IREG with the same GC type as VREG.
262  */
263 guint32
264 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
265 {
266         if (vreg_is_ref (cfg, vreg))
267                 return alloc_ireg_ref (cfg);
268         else if (vreg_is_mp (cfg, vreg))
269                 return alloc_ireg_mp (cfg);
270         else
271                 return alloc_ireg (cfg);
272 }
273
274 guint
275 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
276 {
277         if (type->byref)
278                 return OP_MOVE;
279
280         type = mini_get_underlying_type (type);
281 handle_enum:
282         switch (type->type) {
283         case MONO_TYPE_I1:
284         case MONO_TYPE_U1:
285                 return OP_MOVE;
286         case MONO_TYPE_I2:
287         case MONO_TYPE_U2:
288                 return OP_MOVE;
289         case MONO_TYPE_I4:
290         case MONO_TYPE_U4:
291                 return OP_MOVE;
292         case MONO_TYPE_I:
293         case MONO_TYPE_U:
294         case MONO_TYPE_PTR:
295         case MONO_TYPE_FNPTR:
296                 return OP_MOVE;
297         case MONO_TYPE_CLASS:
298         case MONO_TYPE_STRING:
299         case MONO_TYPE_OBJECT:
300         case MONO_TYPE_SZARRAY:
301         case MONO_TYPE_ARRAY:    
302                 return OP_MOVE;
303         case MONO_TYPE_I8:
304         case MONO_TYPE_U8:
305 #if SIZEOF_REGISTER == 8
306                 return OP_MOVE;
307 #else
308                 return OP_LMOVE;
309 #endif
310         case MONO_TYPE_R4:
311                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
312         case MONO_TYPE_R8:
313                 return OP_FMOVE;
314         case MONO_TYPE_VALUETYPE:
315                 if (type->data.klass->enumtype) {
316                         type = mono_class_enum_basetype (type->data.klass);
317                         goto handle_enum;
318                 }
319                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
320                         return OP_XMOVE;
321                 return OP_VMOVE;
322         case MONO_TYPE_TYPEDBYREF:
323                 return OP_VMOVE;
324         case MONO_TYPE_GENERICINST:
325                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
326                         return OP_XMOVE;
327                 type = &type->data.generic_class->container_class->byval_arg;
328                 goto handle_enum;
329         case MONO_TYPE_VAR:
330         case MONO_TYPE_MVAR:
331                 g_assert (cfg->gshared);
332                 if (mini_type_var_is_vt (type))
333                         return OP_VMOVE;
334                 else
335                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
336         default:
337                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
338         }
339         return -1;
340 }
341
342 void
343 mono_print_bb (MonoBasicBlock *bb, const char *msg)
344 {
345         int i;
346         MonoInst *tree;
347         GString *str = g_string_new ("");
348
349         g_string_append_printf (str, "%s %d: [IN: ", msg, bb->block_num);
350         for (i = 0; i < bb->in_count; ++i)
351                 g_string_append_printf (str, " BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
352         g_string_append_printf (str, ", OUT: ");
353         for (i = 0; i < bb->out_count; ++i)
354                 g_string_append_printf (str, " BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
355         g_string_append_printf (str, " ]\n");
356
357         g_print ("%s", str->str);
358         g_string_free (str, TRUE);
359
360         for (tree = bb->code; tree; tree = tree->next)
361                 mono_print_ins_index (-1, tree);
362 }
363
364 void
365 mono_create_helper_signatures (void)
366 {
367         helper_sig_domain_get = mono_create_icall_signature ("ptr");
368         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
369         helper_sig_llvmonly_imt_trampoline = mono_create_icall_signature ("ptr ptr ptr");
370         helper_sig_jit_thread_attach = mono_create_icall_signature ("ptr ptr");
371         helper_sig_get_tls_tramp = mono_create_icall_signature ("ptr");
372         helper_sig_set_tls_tramp = mono_create_icall_signature ("void ptr");
373 }
374
375 static MONO_NEVER_INLINE void
376 break_on_unverified (void)
377 {
378         if (mini_get_debug_options ()->break_on_unverified)
379                 G_BREAKPOINT ();
380 }
381
382 static MONO_NEVER_INLINE void
383 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
384 {
385         char *method_fname = mono_method_full_name (method, TRUE);
386         char *field_fname = mono_field_full_name (field);
387         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
388         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
389         g_free (method_fname);
390         g_free (field_fname);
391 }
392
393 static MONO_NEVER_INLINE void
394 inline_failure (MonoCompile *cfg, const char *msg)
395 {
396         if (cfg->verbose_level >= 2)
397                 printf ("inline failed: %s\n", msg);
398         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
399 }
400
401 static MONO_NEVER_INLINE void
402 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
403 {
404         if (cfg->verbose_level > 2)                                                                                     \
405                 printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), line);
406         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
407 }
408
409 static MONO_NEVER_INLINE void
410 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
411 {
412         cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), file, line);
413         if (cfg->verbose_level >= 2)
414                 printf ("%s\n", cfg->exception_message);
415         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
416 }
417
418 /*
419  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
420  * foo<T> (int i) { ldarg.0; box T; }
421  */
422 #define UNVERIFIED do { \
423         if (cfg->gsharedvt) { \
424                 if (cfg->verbose_level > 2)                                                                     \
425                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
426                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
427                 goto exception_exit;                                                                                    \
428         }                                                                                                                                       \
429         break_on_unverified ();                                                                                         \
430         goto unverified;                                                                                                        \
431 } while (0)
432
433 #define GET_BBLOCK(cfg,tblock,ip) do {  \
434                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
435                 if (!(tblock)) {        \
436                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
437             NEW_BBLOCK (cfg, (tblock)); \
438                         (tblock)->cil_code = (ip);      \
439                         ADD_BBLOCK (cfg, (tblock));     \
440                 } \
441         } while (0)
442
443 #if defined(TARGET_X86) || defined(TARGET_AMD64)
444 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
445                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
446                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
447                 (dest)->sreg1 = (sr1); \
448                 (dest)->sreg2 = (sr2); \
449                 (dest)->inst_imm = (imm); \
450                 (dest)->backend.shift_amount = (shift); \
451                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
452         } while (0)
453 #endif
454
455 /* Emit conversions so both operands of a binary opcode are of the same type */
456 static void
457 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
458 {
459         MonoInst *arg1 = *arg1_ref;
460         MonoInst *arg2 = *arg2_ref;
461
462         if (cfg->r4fp &&
463                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
464                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
465                 MonoInst *conv;
466
467                 /* Mixing r4/r8 is allowed by the spec */
468                 if (arg1->type == STACK_R4) {
469                         int dreg = alloc_freg (cfg);
470
471                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
472                         conv->type = STACK_R8;
473                         ins->sreg1 = dreg;
474                         *arg1_ref = conv;
475                 }
476                 if (arg2->type == STACK_R4) {
477                         int dreg = alloc_freg (cfg);
478
479                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
480                         conv->type = STACK_R8;
481                         ins->sreg2 = dreg;
482                         *arg2_ref = conv;
483                 }
484         }
485
486 #if SIZEOF_REGISTER == 8
487         /* FIXME: Need to add many more cases */
488         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
489                 MonoInst *widen;
490
491                 int dr = alloc_preg (cfg);
492                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
493                 (ins)->sreg2 = widen->dreg;
494         }
495 #endif
496 }
497
498 #define ADD_BINOP(op) do {      \
499                 MONO_INST_NEW (cfg, ins, (op)); \
500                 sp -= 2;        \
501                 ins->sreg1 = sp [0]->dreg;      \
502                 ins->sreg2 = sp [1]->dreg;      \
503                 type_from_op (cfg, ins, sp [0], sp [1]);        \
504                 CHECK_TYPE (ins);       \
505                 /* Have to insert a widening op */               \
506         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
507         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
508         MONO_ADD_INS ((cfg)->cbb, (ins)); \
509         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
510         } while (0)
511
512 #define ADD_UNOP(op) do {       \
513                 MONO_INST_NEW (cfg, ins, (op)); \
514                 sp--;   \
515                 ins->sreg1 = sp [0]->dreg;      \
516                 type_from_op (cfg, ins, sp [0], NULL);  \
517                 CHECK_TYPE (ins);       \
518         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
519         MONO_ADD_INS ((cfg)->cbb, (ins)); \
520                 *sp++ = mono_decompose_opcode (cfg, ins);       \
521         } while (0)
522
523 #define ADD_BINCOND(next_block) do {    \
524                 MonoInst *cmp;  \
525                 sp -= 2; \
526                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
527                 cmp->sreg1 = sp [0]->dreg;      \
528                 cmp->sreg2 = sp [1]->dreg;      \
529                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
530                 CHECK_TYPE (cmp);       \
531                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
532                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
533                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
534                 GET_BBLOCK (cfg, tblock, target);               \
535                 link_bblock (cfg, cfg->cbb, tblock);    \
536                 ins->inst_true_bb = tblock;     \
537                 if ((next_block)) {     \
538                         link_bblock (cfg, cfg->cbb, (next_block));      \
539                         ins->inst_false_bb = (next_block);      \
540                         start_new_bblock = 1;   \
541                 } else {        \
542                         GET_BBLOCK (cfg, tblock, ip);           \
543                         link_bblock (cfg, cfg->cbb, tblock);    \
544                         ins->inst_false_bb = tblock;    \
545                         start_new_bblock = 2;   \
546                 }       \
547                 if (sp != stack_start) {                                                                        \
548                     handle_stack_args (cfg, stack_start, sp - stack_start); \
549                         CHECK_UNVERIFIABLE (cfg); \
550                 } \
551         MONO_ADD_INS (cfg->cbb, cmp); \
552                 MONO_ADD_INS (cfg->cbb, ins);   \
553         } while (0)
554
555 /* *
556  * link_bblock: Links two basic blocks
557  *
558  * links two basic blocks in the control flow graph, the 'from'
559  * argument is the starting block and the 'to' argument is the block
560  * the control flow ends to after 'from'.
561  */
562 static void
563 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
564 {
565         MonoBasicBlock **newa;
566         int i, found;
567
568 #if 0
569         if (from->cil_code) {
570                 if (to->cil_code)
571                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
572                 else
573                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
574         } else {
575                 if (to->cil_code)
576                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
577                 else
578                         printf ("edge from entry to exit\n");
579         }
580 #endif
581
582         found = FALSE;
583         for (i = 0; i < from->out_count; ++i) {
584                 if (to == from->out_bb [i]) {
585                         found = TRUE;
586                         break;
587                 }
588         }
589         if (!found) {
590                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
591                 for (i = 0; i < from->out_count; ++i) {
592                         newa [i] = from->out_bb [i];
593                 }
594                 newa [i] = to;
595                 from->out_count++;
596                 from->out_bb = newa;
597         }
598
599         found = FALSE;
600         for (i = 0; i < to->in_count; ++i) {
601                 if (from == to->in_bb [i]) {
602                         found = TRUE;
603                         break;
604                 }
605         }
606         if (!found) {
607                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
608                 for (i = 0; i < to->in_count; ++i) {
609                         newa [i] = to->in_bb [i];
610                 }
611                 newa [i] = from;
612                 to->in_count++;
613                 to->in_bb = newa;
614         }
615 }
616
617 void
618 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
619 {
620         link_bblock (cfg, from, to);
621 }
622
623 /**
624  * mono_find_block_region:
625  *
626  *   We mark each basic block with a region ID. We use that to avoid BB
627  *   optimizations when blocks are in different regions.
628  *
629  * Returns:
630  *   A region token that encodes where this region is, and information
631  *   about the clause owner for this block.
632  *
633  *   The region encodes the try/catch/filter clause that owns this block
634  *   as well as the type.  -1 is a special value that represents a block
635  *   that is in none of try/catch/filter.
636  */
637 static int
638 mono_find_block_region (MonoCompile *cfg, int offset)
639 {
640         MonoMethodHeader *header = cfg->header;
641         MonoExceptionClause *clause;
642         int i;
643
644         for (i = 0; i < header->num_clauses; ++i) {
645                 clause = &header->clauses [i];
646                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
647                     (offset < (clause->handler_offset)))
648                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
649                            
650                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
651                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
652                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
653                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
654                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
655                         else
656                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
657                 }
658         }
659         for (i = 0; i < header->num_clauses; ++i) {
660                 clause = &header->clauses [i];
661
662                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
663                         return ((i + 1) << 8) | clause->flags;
664         }
665
666         return -1;
667 }
668
669 static gboolean
670 ip_in_finally_clause (MonoCompile *cfg, int offset)
671 {
672         MonoMethodHeader *header = cfg->header;
673         MonoExceptionClause *clause;
674         int i;
675
676         for (i = 0; i < header->num_clauses; ++i) {
677                 clause = &header->clauses [i];
678                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
679                         continue;
680
681                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
682                         return TRUE;
683         }
684         return FALSE;
685 }
686
687 static GList*
688 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
689 {
690         MonoMethodHeader *header = cfg->header;
691         MonoExceptionClause *clause;
692         int i;
693         GList *res = NULL;
694
695         for (i = 0; i < header->num_clauses; ++i) {
696                 clause = &header->clauses [i];
697                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
698                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
699                         if (clause->flags == type)
700                                 res = g_list_append (res, clause);
701                 }
702         }
703         return res;
704 }
705
706 static void
707 mono_create_spvar_for_region (MonoCompile *cfg, int region)
708 {
709         MonoInst *var;
710
711         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
712         if (var)
713                 return;
714
715         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
716         /* prevent it from being register allocated */
717         var->flags |= MONO_INST_VOLATILE;
718
719         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
720 }
721
722 MonoInst *
723 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
724 {
725         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
726 }
727
728 static MonoInst*
729 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
730 {
731         MonoInst *var;
732
733         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
734         if (var)
735                 return var;
736
737         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
738         /* prevent it from being register allocated */
739         var->flags |= MONO_INST_VOLATILE;
740
741         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
742
743         return var;
744 }
745
746 /*
747  * Returns the type used in the eval stack when @type is loaded.
748  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
749  */
750 void
751 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
752 {
753         MonoClass *klass;
754
755         type = mini_get_underlying_type (type);
756         inst->klass = klass = mono_class_from_mono_type (type);
757         if (type->byref) {
758                 inst->type = STACK_MP;
759                 return;
760         }
761
762 handle_enum:
763         switch (type->type) {
764         case MONO_TYPE_VOID:
765                 inst->type = STACK_INV;
766                 return;
767         case MONO_TYPE_I1:
768         case MONO_TYPE_U1:
769         case MONO_TYPE_I2:
770         case MONO_TYPE_U2:
771         case MONO_TYPE_I4:
772         case MONO_TYPE_U4:
773                 inst->type = STACK_I4;
774                 return;
775         case MONO_TYPE_I:
776         case MONO_TYPE_U:
777         case MONO_TYPE_PTR:
778         case MONO_TYPE_FNPTR:
779                 inst->type = STACK_PTR;
780                 return;
781         case MONO_TYPE_CLASS:
782         case MONO_TYPE_STRING:
783         case MONO_TYPE_OBJECT:
784         case MONO_TYPE_SZARRAY:
785         case MONO_TYPE_ARRAY:    
786                 inst->type = STACK_OBJ;
787                 return;
788         case MONO_TYPE_I8:
789         case MONO_TYPE_U8:
790                 inst->type = STACK_I8;
791                 return;
792         case MONO_TYPE_R4:
793                 inst->type = cfg->r4_stack_type;
794                 break;
795         case MONO_TYPE_R8:
796                 inst->type = STACK_R8;
797                 return;
798         case MONO_TYPE_VALUETYPE:
799                 if (type->data.klass->enumtype) {
800                         type = mono_class_enum_basetype (type->data.klass);
801                         goto handle_enum;
802                 } else {
803                         inst->klass = klass;
804                         inst->type = STACK_VTYPE;
805                         return;
806                 }
807         case MONO_TYPE_TYPEDBYREF:
808                 inst->klass = mono_defaults.typed_reference_class;
809                 inst->type = STACK_VTYPE;
810                 return;
811         case MONO_TYPE_GENERICINST:
812                 type = &type->data.generic_class->container_class->byval_arg;
813                 goto handle_enum;
814         case MONO_TYPE_VAR:
815         case MONO_TYPE_MVAR:
816                 g_assert (cfg->gshared);
817                 if (mini_is_gsharedvt_type (type)) {
818                         g_assert (cfg->gsharedvt);
819                         inst->type = STACK_VTYPE;
820                 } else {
821                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
822                 }
823                 return;
824         default:
825                 g_error ("unknown type 0x%02x in eval stack type", type->type);
826         }
827 }
828
829 /*
830  * The following tables are used to quickly validate the IL code in type_from_op ().
831  */
832 static const char
833 bin_num_table [STACK_MAX] [STACK_MAX] = {
834         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
835         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
836         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
837         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
838         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
839         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
840         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
841         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
842         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
843 };
844
845 static const char 
846 neg_table [] = {
847         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
848 };
849
850 /* reduce the size of this table */
851 static const char
852 bin_int_table [STACK_MAX] [STACK_MAX] = {
853         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
854         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
855         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
856         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
857         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
858         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
859         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
860         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
861 };
862
863 static const char
864 bin_comp_table [STACK_MAX] [STACK_MAX] = {
865 /*      Inv i  L  p  F  &  O  vt r4 */
866         {0},
867         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
868         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
869         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
870         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
871         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
872         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
873         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
874         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
875 };
876
877 /* reduce the size of this table */
878 static const char
879 shift_table [STACK_MAX] [STACK_MAX] = {
880         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
881         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
882         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
883         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
884         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
885         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
886         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
887         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
888 };
889
890 /*
891  * Tables to map from the non-specific opcode to the matching
892  * type-specific opcode.
893  */
894 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
895 static const guint16
896 binops_op_map [STACK_MAX] = {
897         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD, 0, 0, OP_RADD-CEE_ADD
898 };
899
900 /* handles from CEE_NEG to CEE_CONV_U8 */
901 static const guint16
902 unops_op_map [STACK_MAX] = {
903         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG, 0, 0, OP_RNEG-CEE_NEG
904 };
905
906 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
907 static const guint16
908 ovfops_op_map [STACK_MAX] = {
909         0, OP_ICONV_TO_U2-CEE_CONV_U2, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, 0, OP_RCONV_TO_U2-CEE_CONV_U2
910 };
911
912 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
913 static const guint16
914 ovf2ops_op_map [STACK_MAX] = {
915         0, OP_ICONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_LCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_FCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, 0, 0, OP_RCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
916 };
917
918 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
919 static const guint16
920 ovf3ops_op_map [STACK_MAX] = {
921         0, OP_ICONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_LCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_FCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, 0, 0, OP_RCONV_TO_OVF_I1-CEE_CONV_OVF_I1
922 };
923
924 /* handles from CEE_BEQ to CEE_BLT_UN */
925 static const guint16
926 beqops_op_map [STACK_MAX] = {
927         0, OP_IBEQ-CEE_BEQ, OP_LBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_FBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, 0, OP_FBEQ-CEE_BEQ
928 };
929
930 /* handles from CEE_CEQ to CEE_CLT_UN */
931 static const guint16
932 ceqops_op_map [STACK_MAX] = {
933         0, OP_ICEQ-OP_CEQ, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, 0, OP_RCEQ-OP_CEQ
934 };
935
936 /*
937  * Sets ins->type (the type on the eval stack) according to the
938  * type of the opcode and the arguments to it.
939  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
940  *
941  * FIXME: this function sets ins->type unconditionally in some cases, but
942  * it should set it to invalid for some types (a conv.x on an object)
943  */
944 static void
945 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
946 {
947         switch (ins->opcode) {
948         /* binops */
949         case CEE_ADD:
950         case CEE_SUB:
951         case CEE_MUL:
952         case CEE_DIV:
953         case CEE_REM:
954                 /* FIXME: check unverifiable args for STACK_MP */
955                 ins->type = bin_num_table [src1->type] [src2->type];
956                 ins->opcode += binops_op_map [ins->type];
957                 break;
958         case CEE_DIV_UN:
959         case CEE_REM_UN:
960         case CEE_AND:
961         case CEE_OR:
962         case CEE_XOR:
963                 ins->type = bin_int_table [src1->type] [src2->type];
964                 ins->opcode += binops_op_map [ins->type];
965                 break;
966         case CEE_SHL:
967         case CEE_SHR:
968         case CEE_SHR_UN:
969                 ins->type = shift_table [src1->type] [src2->type];
970                 ins->opcode += binops_op_map [ins->type];
971                 break;
972         case OP_COMPARE:
973         case OP_LCOMPARE:
974         case OP_ICOMPARE:
975                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
976                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
977                         ins->opcode = OP_LCOMPARE;
978                 else if (src1->type == STACK_R4)
979                         ins->opcode = OP_RCOMPARE;
980                 else if (src1->type == STACK_R8)
981                         ins->opcode = OP_FCOMPARE;
982                 else
983                         ins->opcode = OP_ICOMPARE;
984                 break;
985         case OP_ICOMPARE_IMM:
986                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
987                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
988                         ins->opcode = OP_LCOMPARE_IMM;          
989                 break;
990         case CEE_BEQ:
991         case CEE_BGE:
992         case CEE_BGT:
993         case CEE_BLE:
994         case CEE_BLT:
995         case CEE_BNE_UN:
996         case CEE_BGE_UN:
997         case CEE_BGT_UN:
998         case CEE_BLE_UN:
999         case CEE_BLT_UN:
1000                 ins->opcode += beqops_op_map [src1->type];
1001                 break;
1002         case OP_CEQ:
1003                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
1004                 ins->opcode += ceqops_op_map [src1->type];
1005                 break;
1006         case OP_CGT:
1007         case OP_CGT_UN:
1008         case OP_CLT:
1009         case OP_CLT_UN:
1010                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
1011                 ins->opcode += ceqops_op_map [src1->type];
1012                 break;
1013         /* unops */
1014         case CEE_NEG:
1015                 ins->type = neg_table [src1->type];
1016                 ins->opcode += unops_op_map [ins->type];
1017                 break;
1018         case CEE_NOT:
1019                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1020                         ins->type = src1->type;
1021                 else
1022                         ins->type = STACK_INV;
1023                 ins->opcode += unops_op_map [ins->type];
1024                 break;
1025         case CEE_CONV_I1:
1026         case CEE_CONV_I2:
1027         case CEE_CONV_I4:
1028         case CEE_CONV_U4:
1029                 ins->type = STACK_I4;
1030                 ins->opcode += unops_op_map [src1->type];
1031                 break;
1032         case CEE_CONV_R_UN:
1033                 ins->type = STACK_R8;
1034                 switch (src1->type) {
1035                 case STACK_I4:
1036                 case STACK_PTR:
1037                         ins->opcode = OP_ICONV_TO_R_UN;
1038                         break;
1039                 case STACK_I8:
1040                         ins->opcode = OP_LCONV_TO_R_UN; 
1041                         break;
1042                 }
1043                 break;
1044         case CEE_CONV_OVF_I1:
1045         case CEE_CONV_OVF_U1:
1046         case CEE_CONV_OVF_I2:
1047         case CEE_CONV_OVF_U2:
1048         case CEE_CONV_OVF_I4:
1049         case CEE_CONV_OVF_U4:
1050                 ins->type = STACK_I4;
1051                 ins->opcode += ovf3ops_op_map [src1->type];
1052                 break;
1053         case CEE_CONV_OVF_I_UN:
1054         case CEE_CONV_OVF_U_UN:
1055                 ins->type = STACK_PTR;
1056                 ins->opcode += ovf2ops_op_map [src1->type];
1057                 break;
1058         case CEE_CONV_OVF_I1_UN:
1059         case CEE_CONV_OVF_I2_UN:
1060         case CEE_CONV_OVF_I4_UN:
1061         case CEE_CONV_OVF_U1_UN:
1062         case CEE_CONV_OVF_U2_UN:
1063         case CEE_CONV_OVF_U4_UN:
1064                 ins->type = STACK_I4;
1065                 ins->opcode += ovf2ops_op_map [src1->type];
1066                 break;
1067         case CEE_CONV_U:
1068                 ins->type = STACK_PTR;
1069                 switch (src1->type) {
1070                 case STACK_I4:
1071                         ins->opcode = OP_ICONV_TO_U;
1072                         break;
1073                 case STACK_PTR:
1074                 case STACK_MP:
1075 #if SIZEOF_VOID_P == 8
1076                         ins->opcode = OP_LCONV_TO_U;
1077 #else
1078                         ins->opcode = OP_MOVE;
1079 #endif
1080                         break;
1081                 case STACK_I8:
1082                         ins->opcode = OP_LCONV_TO_U;
1083                         break;
1084                 case STACK_R8:
1085                         ins->opcode = OP_FCONV_TO_U;
1086                         break;
1087                 }
1088                 break;
1089         case CEE_CONV_I8:
1090         case CEE_CONV_U8:
1091                 ins->type = STACK_I8;
1092                 ins->opcode += unops_op_map [src1->type];
1093                 break;
1094         case CEE_CONV_OVF_I8:
1095         case CEE_CONV_OVF_U8:
1096                 ins->type = STACK_I8;
1097                 ins->opcode += ovf3ops_op_map [src1->type];
1098                 break;
1099         case CEE_CONV_OVF_U8_UN:
1100         case CEE_CONV_OVF_I8_UN:
1101                 ins->type = STACK_I8;
1102                 ins->opcode += ovf2ops_op_map [src1->type];
1103                 break;
1104         case CEE_CONV_R4:
1105                 ins->type = cfg->r4_stack_type;
1106                 ins->opcode += unops_op_map [src1->type];
1107                 break;
1108         case CEE_CONV_R8:
1109                 ins->type = STACK_R8;
1110                 ins->opcode += unops_op_map [src1->type];
1111                 break;
1112         case OP_CKFINITE:
1113                 ins->type = STACK_R8;           
1114                 break;
1115         case CEE_CONV_U2:
1116         case CEE_CONV_U1:
1117                 ins->type = STACK_I4;
1118                 ins->opcode += ovfops_op_map [src1->type];
1119                 break;
1120         case CEE_CONV_I:
1121         case CEE_CONV_OVF_I:
1122         case CEE_CONV_OVF_U:
1123                 ins->type = STACK_PTR;
1124                 ins->opcode += ovfops_op_map [src1->type];
1125                 break;
1126         case CEE_ADD_OVF:
1127         case CEE_ADD_OVF_UN:
1128         case CEE_MUL_OVF:
1129         case CEE_MUL_OVF_UN:
1130         case CEE_SUB_OVF:
1131         case CEE_SUB_OVF_UN:
1132                 ins->type = bin_num_table [src1->type] [src2->type];
1133                 ins->opcode += ovfops_op_map [src1->type];
1134                 if (ins->type == STACK_R8)
1135                         ins->type = STACK_INV;
1136                 break;
1137         case OP_LOAD_MEMBASE:
1138                 ins->type = STACK_PTR;
1139                 break;
1140         case OP_LOADI1_MEMBASE:
1141         case OP_LOADU1_MEMBASE:
1142         case OP_LOADI2_MEMBASE:
1143         case OP_LOADU2_MEMBASE:
1144         case OP_LOADI4_MEMBASE:
1145         case OP_LOADU4_MEMBASE:
1146                 ins->type = STACK_PTR;
1147                 break;
1148         case OP_LOADI8_MEMBASE:
1149                 ins->type = STACK_I8;
1150                 break;
1151         case OP_LOADR4_MEMBASE:
1152                 ins->type = cfg->r4_stack_type;
1153                 break;
1154         case OP_LOADR8_MEMBASE:
1155                 ins->type = STACK_R8;
1156                 break;
1157         default:
1158                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1159                 break;
1160         }
1161
1162         if (ins->type == STACK_MP)
1163                 ins->klass = mono_defaults.object_class;
1164 }
1165
1166 static const char 
1167 ldind_type [] = {
1168         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1169 };
1170
1171 #if 0
1172
1173 static const char
1174 param_table [STACK_MAX] [STACK_MAX] = {
1175         {0},
1176 };
1177
1178 static int
1179 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1180 {
1181         int i;
1182
1183         if (sig->hasthis) {
1184                 switch (args->type) {
1185                 case STACK_I4:
1186                 case STACK_I8:
1187                 case STACK_R8:
1188                 case STACK_VTYPE:
1189                 case STACK_INV:
1190                         return 0;
1191                 }
1192                 args++;
1193         }
1194         for (i = 0; i < sig->param_count; ++i) {
1195                 switch (args [i].type) {
1196                 case STACK_INV:
1197                         return 0;
1198                 case STACK_MP:
1199                         if (!sig->params [i]->byref)
1200                                 return 0;
1201                         continue;
1202                 case STACK_OBJ:
1203                         if (sig->params [i]->byref)
1204                                 return 0;
1205                         switch (sig->params [i]->type) {
1206                         case MONO_TYPE_CLASS:
1207                         case MONO_TYPE_STRING:
1208                         case MONO_TYPE_OBJECT:
1209                         case MONO_TYPE_SZARRAY:
1210                         case MONO_TYPE_ARRAY:
1211                                 break;
1212                         default:
1213                                 return 0;
1214                         }
1215                         continue;
1216                 case STACK_R8:
1217                         if (sig->params [i]->byref)
1218                                 return 0;
1219                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1220                                 return 0;
1221                         continue;
1222                 case STACK_PTR:
1223                 case STACK_I4:
1224                 case STACK_I8:
1225                 case STACK_VTYPE:
1226                         break;
1227                 }
1228                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1229                         return 0;*/
1230         }
1231         return 1;
1232 }
1233 #endif
1234
1235 /*
1236  * When we need a pointer to the current domain many times in a method, we
1237  * call mono_domain_get() once and we store the result in a local variable.
1238  * This function returns the variable that represents the MonoDomain*.
1239  */
1240 inline static MonoInst *
1241 mono_get_domainvar (MonoCompile *cfg)
1242 {
1243         if (!cfg->domainvar)
1244                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1245         return cfg->domainvar;
1246 }
1247
1248 /*
1249  * The got_var contains the address of the Global Offset Table when AOT 
1250  * compiling.
1251  */
1252 MonoInst *
1253 mono_get_got_var (MonoCompile *cfg)
1254 {
1255         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1256                 return NULL;
1257         if (!cfg->got_var) {
1258                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1259         }
1260         return cfg->got_var;
1261 }
1262
1263 static MonoInst *
1264 mono_get_vtable_var (MonoCompile *cfg)
1265 {
1266         g_assert (cfg->gshared);
1267
1268         if (!cfg->rgctx_var) {
1269                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1270                 /* force the var to be stack allocated */
1271                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1272         }
1273
1274         return cfg->rgctx_var;
1275 }
1276
1277 static MonoType*
1278 type_from_stack_type (MonoInst *ins) {
1279         switch (ins->type) {
1280         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1281         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1282         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1283         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1284         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1285         case STACK_MP:
1286                 return &ins->klass->this_arg;
1287         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1288         case STACK_VTYPE: return &ins->klass->byval_arg;
1289         default:
1290                 g_error ("stack type %d to monotype not handled\n", ins->type);
1291         }
1292         return NULL;
1293 }
1294
1295 static G_GNUC_UNUSED int
1296 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1297 {
1298         t = mono_type_get_underlying_type (t);
1299         switch (t->type) {
1300         case MONO_TYPE_I1:
1301         case MONO_TYPE_U1:
1302         case MONO_TYPE_I2:
1303         case MONO_TYPE_U2:
1304         case MONO_TYPE_I4:
1305         case MONO_TYPE_U4:
1306                 return STACK_I4;
1307         case MONO_TYPE_I:
1308         case MONO_TYPE_U:
1309         case MONO_TYPE_PTR:
1310         case MONO_TYPE_FNPTR:
1311                 return STACK_PTR;
1312         case MONO_TYPE_CLASS:
1313         case MONO_TYPE_STRING:
1314         case MONO_TYPE_OBJECT:
1315         case MONO_TYPE_SZARRAY:
1316         case MONO_TYPE_ARRAY:    
1317                 return STACK_OBJ;
1318         case MONO_TYPE_I8:
1319         case MONO_TYPE_U8:
1320                 return STACK_I8;
1321         case MONO_TYPE_R4:
1322                 return cfg->r4_stack_type;
1323         case MONO_TYPE_R8:
1324                 return STACK_R8;
1325         case MONO_TYPE_VALUETYPE:
1326         case MONO_TYPE_TYPEDBYREF:
1327                 return STACK_VTYPE;
1328         case MONO_TYPE_GENERICINST:
1329                 if (mono_type_generic_inst_is_valuetype (t))
1330                         return STACK_VTYPE;
1331                 else
1332                         return STACK_OBJ;
1333                 break;
1334         default:
1335                 g_assert_not_reached ();
1336         }
1337
1338         return -1;
1339 }
1340
1341 static MonoClass*
1342 array_access_to_klass (int opcode)
1343 {
1344         switch (opcode) {
1345         case CEE_LDELEM_U1:
1346                 return mono_defaults.byte_class;
1347         case CEE_LDELEM_U2:
1348                 return mono_defaults.uint16_class;
1349         case CEE_LDELEM_I:
1350         case CEE_STELEM_I:
1351                 return mono_defaults.int_class;
1352         case CEE_LDELEM_I1:
1353         case CEE_STELEM_I1:
1354                 return mono_defaults.sbyte_class;
1355         case CEE_LDELEM_I2:
1356         case CEE_STELEM_I2:
1357                 return mono_defaults.int16_class;
1358         case CEE_LDELEM_I4:
1359         case CEE_STELEM_I4:
1360                 return mono_defaults.int32_class;
1361         case CEE_LDELEM_U4:
1362                 return mono_defaults.uint32_class;
1363         case CEE_LDELEM_I8:
1364         case CEE_STELEM_I8:
1365                 return mono_defaults.int64_class;
1366         case CEE_LDELEM_R4:
1367         case CEE_STELEM_R4:
1368                 return mono_defaults.single_class;
1369         case CEE_LDELEM_R8:
1370         case CEE_STELEM_R8:
1371                 return mono_defaults.double_class;
1372         case CEE_LDELEM_REF:
1373         case CEE_STELEM_REF:
1374                 return mono_defaults.object_class;
1375         default:
1376                 g_assert_not_reached ();
1377         }
1378         return NULL;
1379 }
1380
1381 /*
1382  * We try to share variables when possible
1383  */
1384 static MonoInst *
1385 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1386 {
1387         MonoInst *res;
1388         int pos, vnum;
1389
1390         /* inlining can result in deeper stacks */ 
1391         if (slot >= cfg->header->max_stack)
1392                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1393
1394         pos = ins->type - 1 + slot * STACK_MAX;
1395
1396         switch (ins->type) {
1397         case STACK_I4:
1398         case STACK_I8:
1399         case STACK_R8:
1400         case STACK_PTR:
1401         case STACK_MP:
1402         case STACK_OBJ:
1403                 if ((vnum = cfg->intvars [pos]))
1404                         return cfg->varinfo [vnum];
1405                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1406                 cfg->intvars [pos] = res->inst_c0;
1407                 break;
1408         default:
1409                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1410         }
1411         return res;
1412 }
1413
1414 static void
1415 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1416 {
1417         /* 
1418          * Don't use this if a generic_context is set, since that means AOT can't
1419          * look up the method using just the image+token.
1420          * table == 0 means this is a reference made from a wrapper.
1421          */
1422         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1423                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1424                 jump_info_token->image = image;
1425                 jump_info_token->token = token;
1426                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1427         }
1428 }
1429
1430 /*
1431  * This function is called to handle items that are left on the evaluation stack
1432  * at basic block boundaries. What happens is that we save the values to local variables
1433  * and we reload them later when first entering the target basic block (with the
1434  * handle_loaded_temps () function).
1435  * A single joint point will use the same variables (stored in the array bb->out_stack or
1436  * bb->in_stack, if the basic block is before or after the joint point).
1437  *
1438  * This function needs to be called _before_ emitting the last instruction of
1439  * the bb (i.e. before emitting a branch).
1440  * If the stack merge fails at a join point, cfg->unverifiable is set.
1441  */
1442 static void
1443 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1444 {
1445         int i, bindex;
1446         MonoBasicBlock *bb = cfg->cbb;
1447         MonoBasicBlock *outb;
1448         MonoInst *inst, **locals;
1449         gboolean found;
1450
1451         if (!count)
1452                 return;
1453         if (cfg->verbose_level > 3)
1454                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1455         if (!bb->out_scount) {
1456                 bb->out_scount = count;
1457                 //printf ("bblock %d has out:", bb->block_num);
1458                 found = FALSE;
1459                 for (i = 0; i < bb->out_count; ++i) {
1460                         outb = bb->out_bb [i];
1461                         /* exception handlers are linked, but they should not be considered for stack args */
1462                         if (outb->flags & BB_EXCEPTION_HANDLER)
1463                                 continue;
1464                         //printf (" %d", outb->block_num);
1465                         if (outb->in_stack) {
1466                                 found = TRUE;
1467                                 bb->out_stack = outb->in_stack;
1468                                 break;
1469                         }
1470                 }
1471                 //printf ("\n");
1472                 if (!found) {
1473                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1474                         for (i = 0; i < count; ++i) {
1475                                 /* 
1476                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1477                                  * stack slot and if they are of the same type.
1478                                  * This won't cause conflicts since if 'local' is used to 
1479                                  * store one of the values in the in_stack of a bblock, then
1480                                  * the same variable will be used for the same outgoing stack 
1481                                  * slot as well. 
1482                                  * This doesn't work when inlining methods, since the bblocks
1483                                  * in the inlined methods do not inherit their in_stack from
1484                                  * the bblock they are inlined to. See bug #58863 for an
1485                                  * example.
1486                                  */
1487                                 if (cfg->inlined_method)
1488                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1489                                 else
1490                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1491                         }
1492                 }
1493         }
1494
1495         for (i = 0; i < bb->out_count; ++i) {
1496                 outb = bb->out_bb [i];
1497                 /* exception handlers are linked, but they should not be considered for stack args */
1498                 if (outb->flags & BB_EXCEPTION_HANDLER)
1499                         continue;
1500                 if (outb->in_scount) {
1501                         if (outb->in_scount != bb->out_scount) {
1502                                 cfg->unverifiable = TRUE;
1503                                 return;
1504                         }
1505                         continue; /* check they are the same locals */
1506                 }
1507                 outb->in_scount = count;
1508                 outb->in_stack = bb->out_stack;
1509         }
1510
1511         locals = bb->out_stack;
1512         cfg->cbb = bb;
1513         for (i = 0; i < count; ++i) {
1514                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1515                 inst->cil_code = sp [i]->cil_code;
1516                 sp [i] = locals [i];
1517                 if (cfg->verbose_level > 3)
1518                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1519         }
1520
1521         /*
1522          * It is possible that the out bblocks already have in_stack assigned, and
1523          * the in_stacks differ. In this case, we will store to all the different 
1524          * in_stacks.
1525          */
1526
1527         found = TRUE;
1528         bindex = 0;
1529         while (found) {
1530                 /* Find a bblock which has a different in_stack */
1531                 found = FALSE;
1532                 while (bindex < bb->out_count) {
1533                         outb = bb->out_bb [bindex];
1534                         /* exception handlers are linked, but they should not be considered for stack args */
1535                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1536                                 bindex++;
1537                                 continue;
1538                         }
1539                         if (outb->in_stack != locals) {
1540                                 for (i = 0; i < count; ++i) {
1541                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1542                                         inst->cil_code = sp [i]->cil_code;
1543                                         sp [i] = locals [i];
1544                                         if (cfg->verbose_level > 3)
1545                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1546                                 }
1547                                 locals = outb->in_stack;
1548                                 found = TRUE;
1549                                 break;
1550                         }
1551                         bindex ++;
1552                 }
1553         }
1554 }
1555
1556 static MonoInst*
1557 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1558 {
1559         MonoInst *ins;
1560
1561         if (cfg->compile_aot) {
1562                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1563         } else {
1564                 MonoJumpInfo ji;
1565                 gpointer target;
1566                 MonoError error;
1567
1568                 ji.type = patch_type;
1569                 ji.data.target = data;
1570                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1571                 mono_error_assert_ok (&error);
1572
1573                 EMIT_NEW_PCONST (cfg, ins, target);
1574         }
1575         return ins;
1576 }
1577
1578 MonoInst*
1579 mini_emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1580 {
1581         return emit_runtime_constant (cfg, patch_type, data);
1582 }
1583
1584 static void 
1585 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1586 {
1587         int val_reg;
1588
1589         g_assert (val == 0);
1590
1591         if (align == 0)
1592                 align = 4;
1593
1594         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1595                 switch (size) {
1596                 case 1:
1597                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1598                         return;
1599                 case 2:
1600                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1601                         return;
1602                 case 4:
1603                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1604                         return;
1605 #if SIZEOF_REGISTER == 8
1606                 case 8:
1607                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1608                         return;
1609 #endif
1610                 }
1611         }
1612
1613         val_reg = alloc_preg (cfg);
1614
1615         if (SIZEOF_REGISTER == 8)
1616                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1617         else
1618                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1619
1620         if (align < 4) {
1621                 /* This could be optimized further if neccesary */
1622                 while (size >= 1) {
1623                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1624                         offset += 1;
1625                         size -= 1;
1626                 }
1627                 return;
1628         }       
1629
1630         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1631                 if (offset % 8) {
1632                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1633                         offset += 4;
1634                         size -= 4;
1635                 }
1636                 while (size >= 8) {
1637                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1638                         offset += 8;
1639                         size -= 8;
1640                 }
1641         }       
1642
1643         while (size >= 4) {
1644                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1645                 offset += 4;
1646                 size -= 4;
1647         }
1648         while (size >= 2) {
1649                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1650                 offset += 2;
1651                 size -= 2;
1652         }
1653         while (size >= 1) {
1654                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1655                 offset += 1;
1656                 size -= 1;
1657         }
1658 }
1659
1660 void 
1661 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1662 {
1663         int cur_reg;
1664
1665         if (align == 0)
1666                 align = 4;
1667
1668         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1669         g_assert (size < 10000);
1670
1671         if (align < 4) {
1672                 /* This could be optimized further if neccesary */
1673                 while (size >= 1) {
1674                         cur_reg = alloc_preg (cfg);
1675                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1676                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1677                         doffset += 1;
1678                         soffset += 1;
1679                         size -= 1;
1680                 }
1681         }
1682
1683         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1684                 while (size >= 8) {
1685                         cur_reg = alloc_preg (cfg);
1686                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1687                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1688                         doffset += 8;
1689                         soffset += 8;
1690                         size -= 8;
1691                 }
1692         }       
1693
1694         while (size >= 4) {
1695                 cur_reg = alloc_preg (cfg);
1696                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1697                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1698                 doffset += 4;
1699                 soffset += 4;
1700                 size -= 4;
1701         }
1702         while (size >= 2) {
1703                 cur_reg = alloc_preg (cfg);
1704                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1705                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1706                 doffset += 2;
1707                 soffset += 2;
1708                 size -= 2;
1709         }
1710         while (size >= 1) {
1711                 cur_reg = alloc_preg (cfg);
1712                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1713                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1714                 doffset += 1;
1715                 soffset += 1;
1716                 size -= 1;
1717         }
1718 }
1719
1720 static MonoInst*
1721 mono_create_fast_tls_getter (MonoCompile *cfg, MonoTlsKey key)
1722 {
1723         int tls_offset = mono_tls_get_tls_offset (key);
1724
1725         if (cfg->compile_aot)
1726                 return NULL;
1727
1728         if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
1729                 MonoInst *ins;
1730                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
1731                 ins->dreg = mono_alloc_preg (cfg);
1732                 ins->inst_offset = tls_offset;
1733                 return ins;
1734         }
1735         return NULL;
1736 }
1737
1738 static MonoInst*
1739 mono_create_fast_tls_setter (MonoCompile *cfg, MonoInst* value, MonoTlsKey key)
1740 {
1741         int tls_offset = mono_tls_get_tls_offset (key);
1742
1743         if (cfg->compile_aot)
1744                 return NULL;
1745
1746         if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
1747                 MonoInst *ins;
1748                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1749                 ins->sreg1 = value->dreg;
1750                 ins->inst_offset = tls_offset;
1751                 return ins;
1752         }
1753         return NULL;
1754 }
1755
1756
1757 MonoInst*
1758 mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key)
1759 {
1760         MonoInst *fast_tls = NULL;
1761
1762         if (!mini_get_debug_options ()->use_fallback_tls)
1763                 fast_tls = mono_create_fast_tls_getter (cfg, key);
1764
1765         if (fast_tls) {
1766                 MONO_ADD_INS (cfg->cbb, fast_tls);
1767                 return fast_tls;
1768         }
1769
1770         if (cfg->compile_aot) {
1771                 MonoInst *addr;
1772                 /*
1773                  * tls getters are critical pieces of code and we don't want to resolve them
1774                  * through the standard plt/tramp mechanism since we might expose ourselves
1775                  * to crashes and infinite recursions.
1776                  */
1777                 EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GET_TLS_TRAMP, (void*)key);
1778                 return mono_emit_calli (cfg, helper_sig_get_tls_tramp, NULL, addr, NULL, NULL);
1779         } else {
1780                 gpointer getter = mono_tls_get_tls_getter (key, FALSE);
1781                 return mono_emit_jit_icall (cfg, getter, NULL);
1782         }
1783 }
1784
1785 static MonoInst*
1786 mono_create_tls_set (MonoCompile *cfg, MonoInst *value, MonoTlsKey key)
1787 {
1788         MonoInst *fast_tls = NULL;
1789
1790         if (!mini_get_debug_options ()->use_fallback_tls)
1791                 fast_tls = mono_create_fast_tls_setter (cfg, value, key);
1792
1793         if (fast_tls) {
1794                 MONO_ADD_INS (cfg->cbb, fast_tls);
1795                 return fast_tls;
1796         }
1797
1798         if (cfg->compile_aot) {
1799                 MonoInst *addr;
1800                 EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_SET_TLS_TRAMP, (void*)key);
1801                 return mono_emit_calli (cfg, helper_sig_set_tls_tramp, &value, addr, NULL, NULL);
1802         } else {
1803                 gpointer setter = mono_tls_get_tls_setter (key, FALSE);
1804                 return mono_emit_jit_icall (cfg, setter, &value);
1805         }
1806 }
1807
1808 /*
1809  * emit_push_lmf:
1810  *
1811  *   Emit IR to push the current LMF onto the LMF stack.
1812  */
1813 static void
1814 emit_push_lmf (MonoCompile *cfg)
1815 {
1816         /*
1817          * Emit IR to push the LMF:
1818          * lmf_addr = <lmf_addr from tls>
1819          * lmf->lmf_addr = lmf_addr
1820          * lmf->prev_lmf = *lmf_addr
1821          * *lmf_addr = lmf
1822          */
1823         MonoInst *ins, *lmf_ins;
1824
1825         if (!cfg->lmf_ir)
1826                 return;
1827
1828         if (cfg->lmf_ir_mono_lmf) {
1829                 MonoInst *lmf_vara_ins, *lmf_ins;
1830                 /* Load current lmf */
1831                 lmf_ins = mono_create_tls_get (cfg, TLS_KEY_LMF);
1832                 g_assert (lmf_ins);
1833                 EMIT_NEW_VARLOADA (cfg, lmf_vara_ins, cfg->lmf_var, NULL);
1834                 /* Save previous_lmf */
1835                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_vara_ins->dreg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1836                 /* Set new LMF */
1837                 mono_create_tls_set (cfg, lmf_vara_ins, TLS_KEY_LMF);
1838         } else {
1839                 int lmf_reg, prev_lmf_reg;
1840                 /*
1841                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1842                  */
1843                 if (!cfg->lmf_addr_var)
1844                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1845
1846 #ifdef HOST_WIN32
1847                 ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
1848                 g_assert (ins);
1849                 int jit_tls_dreg = ins->dreg;
1850
1851                 lmf_reg = alloc_preg (cfg);
1852                 EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
1853 #else
1854                 lmf_ins = mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR);
1855                 g_assert (lmf_ins);
1856 #endif
1857                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
1858
1859                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1860                 lmf_reg = ins->dreg;
1861
1862                 prev_lmf_reg = alloc_preg (cfg);
1863                 /* Save previous_lmf */
1864                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
1865                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
1866                 /* Set new lmf */
1867                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
1868         }
1869 }
1870
1871 /*
1872  * emit_pop_lmf:
1873  *
1874  *   Emit IR to pop the current LMF from the LMF stack.
1875  */
1876 static void
1877 emit_pop_lmf (MonoCompile *cfg)
1878 {
1879         int lmf_reg, lmf_addr_reg;
1880         MonoInst *ins;
1881
1882         if (!cfg->lmf_ir)
1883                 return;
1884
1885         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1886         lmf_reg = ins->dreg;
1887
1888         if (cfg->lmf_ir_mono_lmf) {
1889                 /* Load previous_lmf */
1890                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, alloc_preg (cfg), lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1891                 /* Set new LMF */
1892                 mono_create_tls_set (cfg, ins, TLS_KEY_LMF);
1893         } else {
1894                 int prev_lmf_reg;
1895                 /*
1896                  * Emit IR to pop the LMF:
1897                  * *(lmf->lmf_addr) = lmf->prev_lmf
1898                  */
1899                 /* This could be called before emit_push_lmf () */
1900                 if (!cfg->lmf_addr_var)
1901                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1902                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
1903
1904                 prev_lmf_reg = alloc_preg (cfg);
1905                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1906                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
1907         }
1908 }
1909
1910 static void
1911 emit_instrumentation_call (MonoCompile *cfg, void *func)
1912 {
1913         MonoInst *iargs [1];
1914
1915         /*
1916          * Avoid instrumenting inlined methods since it can
1917          * distort profiling results.
1918          */
1919         if (cfg->method != cfg->current_method)
1920                 return;
1921
1922         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
1923                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
1924                 mono_emit_jit_icall (cfg, func, iargs);
1925         }
1926 }
1927
1928 static int
1929 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
1930 {
1931 handle_enum:
1932         type = mini_get_underlying_type (type);
1933         switch (type->type) {
1934         case MONO_TYPE_VOID:
1935                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
1936         case MONO_TYPE_I1:
1937         case MONO_TYPE_U1:
1938         case MONO_TYPE_I2:
1939         case MONO_TYPE_U2:
1940         case MONO_TYPE_I4:
1941         case MONO_TYPE_U4:
1942                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1943         case MONO_TYPE_I:
1944         case MONO_TYPE_U:
1945         case MONO_TYPE_PTR:
1946         case MONO_TYPE_FNPTR:
1947                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1948         case MONO_TYPE_CLASS:
1949         case MONO_TYPE_STRING:
1950         case MONO_TYPE_OBJECT:
1951         case MONO_TYPE_SZARRAY:
1952         case MONO_TYPE_ARRAY:    
1953                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1954         case MONO_TYPE_I8:
1955         case MONO_TYPE_U8:
1956                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
1957         case MONO_TYPE_R4:
1958                 if (cfg->r4fp)
1959                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
1960                 else
1961                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1962         case MONO_TYPE_R8:
1963                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1964         case MONO_TYPE_VALUETYPE:
1965                 if (type->data.klass->enumtype) {
1966                         type = mono_class_enum_basetype (type->data.klass);
1967                         goto handle_enum;
1968                 } else
1969                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1970         case MONO_TYPE_TYPEDBYREF:
1971                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1972         case MONO_TYPE_GENERICINST:
1973                 type = &type->data.generic_class->container_class->byval_arg;
1974                 goto handle_enum;
1975         case MONO_TYPE_VAR:
1976         case MONO_TYPE_MVAR:
1977                 /* gsharedvt */
1978                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1979         default:
1980                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1981         }
1982         return -1;
1983 }
1984
1985 //XXX this ignores if t is byref
1986 #define MONO_TYPE_IS_PRIMITIVE_SCALAR(t) ((((((t)->type >= MONO_TYPE_BOOLEAN && (t)->type <= MONO_TYPE_U8) || ((t)->type >= MONO_TYPE_I && (t)->type <= MONO_TYPE_U)))))
1987
1988 /*
1989  * target_type_is_incompatible:
1990  * @cfg: MonoCompile context
1991  *
1992  * Check that the item @arg on the evaluation stack can be stored
1993  * in the target type (can be a local, or field, etc).
1994  * The cfg arg can be used to check if we need verification or just
1995  * validity checks.
1996  *
1997  * Returns: non-0 value if arg can't be stored on a target.
1998  */
1999 static int
2000 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2001 {
2002         MonoType *simple_type;
2003         MonoClass *klass;
2004
2005         if (target->byref) {
2006                 /* FIXME: check that the pointed to types match */
2007                 if (arg->type == STACK_MP) {
2008                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
2009                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
2010                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
2011
2012                         /* if the target is native int& or same type */
2013                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
2014                                 return 0;
2015
2016                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
2017                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
2018                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
2019                                 return 0;
2020                         return 1;
2021                 }
2022                 if (arg->type == STACK_PTR)
2023                         return 0;
2024                 return 1;
2025         }
2026
2027         simple_type = mini_get_underlying_type (target);
2028         switch (simple_type->type) {
2029         case MONO_TYPE_VOID:
2030                 return 1;
2031         case MONO_TYPE_I1:
2032         case MONO_TYPE_U1:
2033         case MONO_TYPE_I2:
2034         case MONO_TYPE_U2:
2035         case MONO_TYPE_I4:
2036         case MONO_TYPE_U4:
2037                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2038                         return 1;
2039                 return 0;
2040         case MONO_TYPE_PTR:
2041                 /* STACK_MP is needed when setting pinned locals */
2042                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2043                         return 1;
2044                 return 0;
2045         case MONO_TYPE_I:
2046         case MONO_TYPE_U:
2047         case MONO_TYPE_FNPTR:
2048                 /* 
2049                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2050                  * in native int. (#688008).
2051                  */
2052                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2053                         return 1;
2054                 return 0;
2055         case MONO_TYPE_CLASS:
2056         case MONO_TYPE_STRING:
2057         case MONO_TYPE_OBJECT:
2058         case MONO_TYPE_SZARRAY:
2059         case MONO_TYPE_ARRAY:    
2060                 if (arg->type != STACK_OBJ)
2061                         return 1;
2062                 /* FIXME: check type compatibility */
2063                 return 0;
2064         case MONO_TYPE_I8:
2065         case MONO_TYPE_U8:
2066                 if (arg->type != STACK_I8)
2067                         return 1;
2068                 return 0;
2069         case MONO_TYPE_R4:
2070                 if (arg->type != cfg->r4_stack_type)
2071                         return 1;
2072                 return 0;
2073         case MONO_TYPE_R8:
2074                 if (arg->type != STACK_R8)
2075                         return 1;
2076                 return 0;
2077         case MONO_TYPE_VALUETYPE:
2078                 if (arg->type != STACK_VTYPE)
2079                         return 1;
2080                 klass = mono_class_from_mono_type (simple_type);
2081                 if (klass != arg->klass)
2082                         return 1;
2083                 return 0;
2084         case MONO_TYPE_TYPEDBYREF:
2085                 if (arg->type != STACK_VTYPE)
2086                         return 1;
2087                 klass = mono_class_from_mono_type (simple_type);
2088                 if (klass != arg->klass)
2089                         return 1;
2090                 return 0;
2091         case MONO_TYPE_GENERICINST:
2092                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2093                         MonoClass *target_class;
2094                         if (arg->type != STACK_VTYPE)
2095                                 return 1;
2096                         klass = mono_class_from_mono_type (simple_type);
2097                         target_class = mono_class_from_mono_type (target);
2098                         /* The second cases is needed when doing partial sharing */
2099                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2100                                 return 1;
2101                         return 0;
2102                 } else {
2103                         if (arg->type != STACK_OBJ)
2104                                 return 1;
2105                         /* FIXME: check type compatibility */
2106                         return 0;
2107                 }
2108         case MONO_TYPE_VAR:
2109         case MONO_TYPE_MVAR:
2110                 g_assert (cfg->gshared);
2111                 if (mini_type_var_is_vt (simple_type)) {
2112                         if (arg->type != STACK_VTYPE)
2113                                 return 1;
2114                 } else {
2115                         if (arg->type != STACK_OBJ)
2116                                 return 1;
2117                 }
2118                 return 0;
2119         default:
2120                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2121         }
2122         return 1;
2123 }
2124
2125 /*
2126  * Prepare arguments for passing to a function call.
2127  * Return a non-zero value if the arguments can't be passed to the given
2128  * signature.
2129  * The type checks are not yet complete and some conversions may need
2130  * casts on 32 or 64 bit architectures.
2131  *
2132  * FIXME: implement this using target_type_is_incompatible ()
2133  */
2134 static int
2135 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2136 {
2137         MonoType *simple_type;
2138         int i;
2139
2140         if (sig->hasthis) {
2141                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2142                         return 1;
2143                 args++;
2144         }
2145         for (i = 0; i < sig->param_count; ++i) {
2146                 if (sig->params [i]->byref) {
2147                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2148                                 return 1;
2149                         continue;
2150                 }
2151                 simple_type = mini_get_underlying_type (sig->params [i]);
2152 handle_enum:
2153                 switch (simple_type->type) {
2154                 case MONO_TYPE_VOID:
2155                         return 1;
2156                         continue;
2157                 case MONO_TYPE_I1:
2158                 case MONO_TYPE_U1:
2159                 case MONO_TYPE_I2:
2160                 case MONO_TYPE_U2:
2161                 case MONO_TYPE_I4:
2162                 case MONO_TYPE_U4:
2163                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2164                                 return 1;
2165                         continue;
2166                 case MONO_TYPE_I:
2167                 case MONO_TYPE_U:
2168                 case MONO_TYPE_PTR:
2169                 case MONO_TYPE_FNPTR:
2170                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2171                                 return 1;
2172                         continue;
2173                 case MONO_TYPE_CLASS:
2174                 case MONO_TYPE_STRING:
2175                 case MONO_TYPE_OBJECT:
2176                 case MONO_TYPE_SZARRAY:
2177                 case MONO_TYPE_ARRAY:    
2178                         if (args [i]->type != STACK_OBJ)
2179                                 return 1;
2180                         continue;
2181                 case MONO_TYPE_I8:
2182                 case MONO_TYPE_U8:
2183                         if (args [i]->type != STACK_I8)
2184                                 return 1;
2185                         continue;
2186                 case MONO_TYPE_R4:
2187                         if (args [i]->type != cfg->r4_stack_type)
2188                                 return 1;
2189                         continue;
2190                 case MONO_TYPE_R8:
2191                         if (args [i]->type != STACK_R8)
2192                                 return 1;
2193                         continue;
2194                 case MONO_TYPE_VALUETYPE:
2195                         if (simple_type->data.klass->enumtype) {
2196                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2197                                 goto handle_enum;
2198                         }
2199                         if (args [i]->type != STACK_VTYPE)
2200                                 return 1;
2201                         continue;
2202                 case MONO_TYPE_TYPEDBYREF:
2203                         if (args [i]->type != STACK_VTYPE)
2204                                 return 1;
2205                         continue;
2206                 case MONO_TYPE_GENERICINST:
2207                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2208                         goto handle_enum;
2209                 case MONO_TYPE_VAR:
2210                 case MONO_TYPE_MVAR:
2211                         /* gsharedvt */
2212                         if (args [i]->type != STACK_VTYPE)
2213                                 return 1;
2214                         continue;
2215                 default:
2216                         g_error ("unknown type 0x%02x in check_call_signature",
2217                                  simple_type->type);
2218                 }
2219         }
2220         return 0;
2221 }
2222
2223 static int
2224 callvirt_to_call (int opcode)
2225 {
2226         switch (opcode) {
2227         case OP_CALL_MEMBASE:
2228                 return OP_CALL;
2229         case OP_VOIDCALL_MEMBASE:
2230                 return OP_VOIDCALL;
2231         case OP_FCALL_MEMBASE:
2232                 return OP_FCALL;
2233         case OP_RCALL_MEMBASE:
2234                 return OP_RCALL;
2235         case OP_VCALL_MEMBASE:
2236                 return OP_VCALL;
2237         case OP_LCALL_MEMBASE:
2238                 return OP_LCALL;
2239         default:
2240                 g_assert_not_reached ();
2241         }
2242
2243         return -1;
2244 }
2245
2246 static int
2247 callvirt_to_call_reg (int opcode)
2248 {
2249         switch (opcode) {
2250         case OP_CALL_MEMBASE:
2251                 return OP_CALL_REG;
2252         case OP_VOIDCALL_MEMBASE:
2253                 return OP_VOIDCALL_REG;
2254         case OP_FCALL_MEMBASE:
2255                 return OP_FCALL_REG;
2256         case OP_RCALL_MEMBASE:
2257                 return OP_RCALL_REG;
2258         case OP_VCALL_MEMBASE:
2259                 return OP_VCALL_REG;
2260         case OP_LCALL_MEMBASE:
2261                 return OP_LCALL_REG;
2262         default:
2263                 g_assert_not_reached ();
2264         }
2265
2266         return -1;
2267 }
2268
2269 /* Either METHOD or IMT_ARG needs to be set */
2270 static void
2271 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2272 {
2273         int method_reg;
2274
2275         if (COMPILE_LLVM (cfg)) {
2276                 if (imt_arg) {
2277                         method_reg = alloc_preg (cfg);
2278                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2279                 } else {
2280                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2281                         method_reg = ins->dreg;
2282                 }
2283
2284 #ifdef ENABLE_LLVM
2285                 call->imt_arg_reg = method_reg;
2286 #endif
2287                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2288                 return;
2289         }
2290
2291         if (imt_arg) {
2292                 method_reg = alloc_preg (cfg);
2293                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2294         } else {
2295                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2296                 method_reg = ins->dreg;
2297         }
2298
2299         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2300 }
2301
2302 static MonoJumpInfo *
2303 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2304 {
2305         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2306
2307         ji->ip.i = ip;
2308         ji->type = type;
2309         ji->data.target = target;
2310
2311         return ji;
2312 }
2313
2314 static int
2315 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2316 {
2317         if (cfg->gshared)
2318                 return mono_class_check_context_used (klass);
2319         else
2320                 return 0;
2321 }
2322
2323 static int
2324 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2325 {
2326         if (cfg->gshared)
2327                 return mono_method_check_context_used (method);
2328         else
2329                 return 0;
2330 }
2331
2332 /*
2333  * check_method_sharing:
2334  *
2335  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2336  */
2337 static void
2338 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2339 {
2340         gboolean pass_vtable = FALSE;
2341         gboolean pass_mrgctx = FALSE;
2342
2343         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2344                 (mono_class_is_ginst (cmethod->klass) || mono_class_is_gtd (cmethod->klass))) {
2345                 gboolean sharable = FALSE;
2346
2347                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2348                         sharable = TRUE;
2349
2350                 /*
2351                  * Pass vtable iff target method might
2352                  * be shared, which means that sharing
2353                  * is enabled for its class and its
2354                  * context is sharable (and it's not a
2355                  * generic method).
2356                  */
2357                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2358                         pass_vtable = TRUE;
2359         }
2360
2361         if (mini_method_get_context (cmethod) &&
2362                 mini_method_get_context (cmethod)->method_inst) {
2363                 g_assert (!pass_vtable);
2364
2365                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2366                         pass_mrgctx = TRUE;
2367                 } else {
2368                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2369                                 pass_mrgctx = TRUE;
2370                 }
2371         }
2372
2373         if (out_pass_vtable)
2374                 *out_pass_vtable = pass_vtable;
2375         if (out_pass_mrgctx)
2376                 *out_pass_mrgctx = pass_mrgctx;
2377 }
2378
2379 inline static MonoCallInst *
2380 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2381                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2382 {
2383         MonoType *sig_ret;
2384         MonoCallInst *call;
2385 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2386         int i;
2387 #endif
2388
2389         if (cfg->llvm_only)
2390                 tail = FALSE;
2391
2392         if (tail) {
2393                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2394
2395                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2396         } else
2397                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2398
2399         call->args = args;
2400         call->signature = sig;
2401         call->rgctx_reg = rgctx;
2402         sig_ret = mini_get_underlying_type (sig->ret);
2403
2404         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2405
2406         if (tail) {
2407                 if (mini_type_is_vtype (sig_ret)) {
2408                         call->vret_var = cfg->vret_addr;
2409                         //g_assert_not_reached ();
2410                 }
2411         } else if (mini_type_is_vtype (sig_ret)) {
2412                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2413                 MonoInst *loada;
2414
2415                 temp->backend.is_pinvoke = sig->pinvoke;
2416
2417                 /*
2418                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2419                  * address of return value to increase optimization opportunities.
2420                  * Before vtype decomposition, the dreg of the call ins itself represents the
2421                  * fact the call modifies the return value. After decomposition, the call will
2422                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2423                  * will be transformed into an LDADDR.
2424                  */
2425                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2426                 loada->dreg = alloc_preg (cfg);
2427                 loada->inst_p0 = temp;
2428                 /* We reference the call too since call->dreg could change during optimization */
2429                 loada->inst_p1 = call;
2430                 MONO_ADD_INS (cfg->cbb, loada);
2431
2432                 call->inst.dreg = temp->dreg;
2433
2434                 call->vret_var = loada;
2435         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2436                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2437
2438 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2439         if (COMPILE_SOFT_FLOAT (cfg)) {
2440                 /* 
2441                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2442                  * an icall, but that cannot be done during the call sequence since it would clobber
2443                  * the call registers + the stack. So we do it before emitting the call.
2444                  */
2445                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2446                         MonoType *t;
2447                         MonoInst *in = call->args [i];
2448
2449                         if (i >= sig->hasthis)
2450                                 t = sig->params [i - sig->hasthis];
2451                         else
2452                                 t = &mono_defaults.int_class->byval_arg;
2453                         t = mono_type_get_underlying_type (t);
2454
2455                         if (!t->byref && t->type == MONO_TYPE_R4) {
2456                                 MonoInst *iargs [1];
2457                                 MonoInst *conv;
2458
2459                                 iargs [0] = in;
2460                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2461
2462                                 /* The result will be in an int vreg */
2463                                 call->args [i] = conv;
2464                         }
2465                 }
2466         }
2467 #endif
2468
2469         call->need_unbox_trampoline = unbox_trampoline;
2470
2471 #ifdef ENABLE_LLVM
2472         if (COMPILE_LLVM (cfg))
2473                 mono_llvm_emit_call (cfg, call);
2474         else
2475                 mono_arch_emit_call (cfg, call);
2476 #else
2477         mono_arch_emit_call (cfg, call);
2478 #endif
2479
2480         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2481         cfg->flags |= MONO_CFG_HAS_CALLS;
2482         
2483         return call;
2484 }
2485
2486 static void
2487 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2488 {
2489         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2490         cfg->uses_rgctx_reg = TRUE;
2491         call->rgctx_reg = TRUE;
2492 #ifdef ENABLE_LLVM
2493         call->rgctx_arg_reg = rgctx_reg;
2494 #endif
2495 }       
2496
2497 inline static MonoInst*
2498 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2499 {
2500         MonoCallInst *call;
2501         MonoInst *ins;
2502         int rgctx_reg = -1;
2503         gboolean check_sp = FALSE;
2504
2505         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2506                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2507
2508                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2509                         check_sp = TRUE;
2510         }
2511
2512         if (rgctx_arg) {
2513                 rgctx_reg = mono_alloc_preg (cfg);
2514                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2515         }
2516
2517         if (check_sp) {
2518                 if (!cfg->stack_inbalance_var)
2519                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2520
2521                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2522                 ins->dreg = cfg->stack_inbalance_var->dreg;
2523                 MONO_ADD_INS (cfg->cbb, ins);
2524         }
2525
2526         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2527
2528         call->inst.sreg1 = addr->dreg;
2529
2530         if (imt_arg)
2531                 emit_imt_argument (cfg, call, NULL, imt_arg);
2532
2533         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2534
2535         if (check_sp) {
2536                 int sp_reg;
2537
2538                 sp_reg = mono_alloc_preg (cfg);
2539
2540                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2541                 ins->dreg = sp_reg;
2542                 MONO_ADD_INS (cfg->cbb, ins);
2543
2544                 /* Restore the stack so we don't crash when throwing the exception */
2545                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2546                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2547                 MONO_ADD_INS (cfg->cbb, ins);
2548
2549                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2550                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2551         }
2552
2553         if (rgctx_arg)
2554                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2555
2556         return (MonoInst*)call;
2557 }
2558
2559 static MonoInst*
2560 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2561
2562 static MonoInst*
2563 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2564
2565 static MonoInst*
2566 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2567                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2568 {
2569 #ifndef DISABLE_REMOTING
2570         gboolean might_be_remote = FALSE;
2571 #endif
2572         gboolean virtual_ = this_ins != NULL;
2573         gboolean enable_for_aot = TRUE;
2574         int context_used;
2575         MonoCallInst *call;
2576         MonoInst *call_target = NULL;
2577         int rgctx_reg = 0;
2578         gboolean need_unbox_trampoline;
2579
2580         if (!sig)
2581                 sig = mono_method_signature (method);
2582
2583         if (cfg->llvm_only && (mono_class_is_interface (method->klass)))
2584                 g_assert_not_reached ();
2585
2586         if (rgctx_arg) {
2587                 rgctx_reg = mono_alloc_preg (cfg);
2588                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2589         }
2590
2591         if (method->string_ctor) {
2592                 /* Create the real signature */
2593                 /* FIXME: Cache these */
2594                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2595                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2596
2597                 sig = ctor_sig;
2598         }
2599
2600         context_used = mini_method_check_context_used (cfg, method);
2601
2602 #ifndef DISABLE_REMOTING
2603         might_be_remote = this_ins && sig->hasthis &&
2604                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2605                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2606
2607         if (might_be_remote && context_used) {
2608                 MonoInst *addr;
2609
2610                 g_assert (cfg->gshared);
2611
2612                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2613
2614                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2615         }
2616 #endif
2617
2618         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2619                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2620
2621         need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass);
2622
2623         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2624
2625 #ifndef DISABLE_REMOTING
2626         if (might_be_remote)
2627                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2628         else
2629 #endif
2630                 call->method = method;
2631         call->inst.flags |= MONO_INST_HAS_METHOD;
2632         call->inst.inst_left = this_ins;
2633         call->tail_call = tail;
2634
2635         if (virtual_) {
2636                 int vtable_reg, slot_reg, this_reg;
2637                 int offset;
2638
2639                 this_reg = this_ins->dreg;
2640
2641                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2642                         MonoInst *dummy_use;
2643
2644                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2645
2646                         /* Make a call to delegate->invoke_impl */
2647                         call->inst.inst_basereg = this_reg;
2648                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2649                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2650
2651                         /* We must emit a dummy use here because the delegate trampoline will
2652                         replace the 'this' argument with the delegate target making this activation
2653                         no longer a root for the delegate.
2654                         This is an issue for delegates that target collectible code such as dynamic
2655                         methods of GC'able assemblies.
2656
2657                         For a test case look into #667921.
2658
2659                         FIXME: a dummy use is not the best way to do it as the local register allocator
2660                         will put it on a caller save register and spil it around the call. 
2661                         Ideally, we would either put it on a callee save register or only do the store part.  
2662                          */
2663                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2664
2665                         return (MonoInst*)call;
2666                 }
2667
2668                 if ((!cfg->compile_aot || enable_for_aot) && 
2669                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2670                          (MONO_METHOD_IS_FINAL (method) &&
2671                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2672                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2673                         /* 
2674                          * the method is not virtual, we just need to ensure this is not null
2675                          * and then we can call the method directly.
2676                          */
2677 #ifndef DISABLE_REMOTING
2678                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2679                                 /* 
2680                                  * The check above ensures method is not gshared, this is needed since
2681                                  * gshared methods can't have wrappers.
2682                                  */
2683                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2684                         }
2685 #endif
2686
2687                         if (!method->string_ctor)
2688                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2689
2690                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2691                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2692                         /*
2693                          * the method is virtual, but we can statically dispatch since either
2694                          * it's class or the method itself are sealed.
2695                          * But first we need to ensure it's not a null reference.
2696                          */
2697                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2698
2699                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2700                 } else if (call_target) {
2701                         vtable_reg = alloc_preg (cfg);
2702                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2703
2704                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2705                         call->inst.sreg1 = call_target->dreg;
2706                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2707                 } else {
2708                         vtable_reg = alloc_preg (cfg);
2709                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2710                         if (mono_class_is_interface (method->klass)) {
2711                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2712                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2713                                 slot_reg = vtable_reg;
2714                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2715                         } else {
2716                                 slot_reg = vtable_reg;
2717                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2718                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2719                                 if (imt_arg) {
2720                                         g_assert (mono_method_signature (method)->generic_param_count);
2721                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2722                                 }
2723                         }
2724
2725                         call->inst.sreg1 = slot_reg;
2726                         call->inst.inst_offset = offset;
2727                         call->is_virtual = TRUE;
2728                 }
2729         }
2730
2731         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2732
2733         if (rgctx_arg)
2734                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2735
2736         return (MonoInst*)call;
2737 }
2738
2739 MonoInst*
2740 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2741 {
2742         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2743 }
2744
2745 MonoInst*
2746 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2747                                            MonoInst **args)
2748 {
2749         MonoCallInst *call;
2750
2751         g_assert (sig);
2752
2753         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2754         call->fptr = func;
2755
2756         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2757
2758         return (MonoInst*)call;
2759 }
2760
2761 MonoInst*
2762 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2763 {
2764         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2765
2766         g_assert (info);
2767
2768         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2769 }
2770
2771 /*
2772  * mono_emit_abs_call:
2773  *
2774  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2775  */
2776 inline static MonoInst*
2777 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2778                                         MonoMethodSignature *sig, MonoInst **args)
2779 {
2780         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2781         MonoInst *ins;
2782
2783         /* 
2784          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2785          * handle it.
2786          */
2787         if (cfg->abs_patches == NULL)
2788                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2789         g_hash_table_insert (cfg->abs_patches, ji, ji);
2790         ins = mono_emit_native_call (cfg, ji, sig, args);
2791         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2792         return ins;
2793 }
2794
2795 static MonoMethodSignature*
2796 sig_to_rgctx_sig (MonoMethodSignature *sig)
2797 {
2798         // FIXME: memory allocation
2799         MonoMethodSignature *res;
2800         int i;
2801
2802         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2803         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2804         res->param_count = sig->param_count + 1;
2805         for (i = 0; i < sig->param_count; ++i)
2806                 res->params [i] = sig->params [i];
2807         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
2808         return res;
2809 }
2810
2811 /* Make an indirect call to FSIG passing an additional argument */
2812 static MonoInst*
2813 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
2814 {
2815         MonoMethodSignature *csig;
2816         MonoInst *args_buf [16];
2817         MonoInst **args;
2818         int i, pindex, tmp_reg;
2819
2820         /* Make a call with an rgctx/extra arg */
2821         if (fsig->param_count + 2 < 16)
2822                 args = args_buf;
2823         else
2824                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
2825         pindex = 0;
2826         if (fsig->hasthis)
2827                 args [pindex ++] = orig_args [0];
2828         for (i = 0; i < fsig->param_count; ++i)
2829                 args [pindex ++] = orig_args [fsig->hasthis + i];
2830         tmp_reg = alloc_preg (cfg);
2831         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
2832         csig = sig_to_rgctx_sig (fsig);
2833         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
2834 }
2835
2836 /* Emit an indirect call to the function descriptor ADDR */
2837 static MonoInst*
2838 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
2839 {
2840         int addr_reg, arg_reg;
2841         MonoInst *call_target;
2842
2843         g_assert (cfg->llvm_only);
2844
2845         /*
2846          * addr points to a <addr, arg> pair, load both of them, and
2847          * make a call to addr, passing arg as an extra arg.
2848          */
2849         addr_reg = alloc_preg (cfg);
2850         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
2851         arg_reg = alloc_preg (cfg);
2852         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
2853
2854         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
2855 }
2856
2857 static gboolean
2858 direct_icalls_enabled (MonoCompile *cfg)
2859 {
2860         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
2861 #ifdef TARGET_AMD64
2862         if (cfg->compile_llvm && !cfg->llvm_only)
2863                 return FALSE;
2864 #endif
2865         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
2866                 return FALSE;
2867         return TRUE;
2868 }
2869
2870 MonoInst*
2871 mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
2872 {
2873         /*
2874          * Call the jit icall without a wrapper if possible.
2875          * The wrapper is needed for the following reasons:
2876          * - to handle exceptions thrown using mono_raise_exceptions () from the
2877          *   icall function. The EH code needs the lmf frame pushed by the
2878          *   wrapper to be able to unwind back to managed code.
2879          * - to be able to do stack walks for asynchronously suspended
2880          *   threads when debugging.
2881          */
2882         if (info->no_raise && direct_icalls_enabled (cfg)) {
2883                 char *name;
2884                 int costs;
2885
2886                 if (!info->wrapper_method) {
2887                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
2888                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
2889                         g_free (name);
2890                         mono_memory_barrier ();
2891                 }
2892
2893                 /*
2894                  * Inline the wrapper method, which is basically a call to the C icall, and
2895                  * an exception check.
2896                  */
2897                 costs = inline_method (cfg, info->wrapper_method, NULL,
2898                                                            args, NULL, il_offset, TRUE);
2899                 g_assert (costs > 0);
2900                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
2901
2902                 return args [0];
2903         } else {
2904                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2905         }
2906 }
2907  
2908 static MonoInst*
2909 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2910 {
2911         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2912                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2913                         int widen_op = -1;
2914
2915                         /* 
2916                          * Native code might return non register sized integers 
2917                          * without initializing the upper bits.
2918                          */
2919                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2920                         case OP_LOADI1_MEMBASE:
2921                                 widen_op = OP_ICONV_TO_I1;
2922                                 break;
2923                         case OP_LOADU1_MEMBASE:
2924                                 widen_op = OP_ICONV_TO_U1;
2925                                 break;
2926                         case OP_LOADI2_MEMBASE:
2927                                 widen_op = OP_ICONV_TO_I2;
2928                                 break;
2929                         case OP_LOADU2_MEMBASE:
2930                                 widen_op = OP_ICONV_TO_U2;
2931                                 break;
2932                         default:
2933                                 break;
2934                         }
2935
2936                         if (widen_op != -1) {
2937                                 int dreg = alloc_preg (cfg);
2938                                 MonoInst *widen;
2939
2940                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2941                                 widen->type = ins->type;
2942                                 ins = widen;
2943                         }
2944                 }
2945         }
2946
2947         return ins;
2948 }
2949
2950
2951 static void
2952 emit_method_access_failure (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
2953 {
2954         MonoInst *args [16];
2955
2956         args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (caller), caller, MONO_RGCTX_INFO_METHOD);
2957         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (callee), callee, MONO_RGCTX_INFO_METHOD);
2958
2959         mono_emit_jit_icall (cfg, mono_throw_method_access, args);
2960 }
2961
2962 static MonoMethod*
2963 get_memcpy_method (void)
2964 {
2965         static MonoMethod *memcpy_method = NULL;
2966         if (!memcpy_method) {
2967                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2968                 if (!memcpy_method)
2969                         g_error ("Old corlib found. Install a new one");
2970         }
2971         return memcpy_method;
2972 }
2973
2974 static void
2975 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
2976 {
2977         MonoClassField *field;
2978         gpointer iter = NULL;
2979
2980         while ((field = mono_class_get_fields (klass, &iter))) {
2981                 int foffset;
2982
2983                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2984                         continue;
2985                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2986                 if (mini_type_is_reference (mono_field_get_type (field))) {
2987                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2988                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2989                 } else {
2990                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2991                         if (field_class->has_references)
2992                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
2993                 }
2994         }
2995 }
2996
2997 static void
2998 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
2999 {
3000         int card_table_shift_bits;
3001         gpointer card_table_mask;
3002         guint8 *card_table;
3003         MonoInst *dummy_use;
3004         int nursery_shift_bits;
3005         size_t nursery_size;
3006
3007         if (!cfg->gen_write_barriers)
3008                 return;
3009
3010         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3011
3012         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3013
3014         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3015                 MonoInst *wbarrier;
3016
3017                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3018                 wbarrier->sreg1 = ptr->dreg;
3019                 wbarrier->sreg2 = value->dreg;
3020                 MONO_ADD_INS (cfg->cbb, wbarrier);
3021         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3022                 int offset_reg = alloc_preg (cfg);
3023                 int card_reg;
3024                 MonoInst *ins;
3025
3026                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3027                 if (card_table_mask)
3028                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3029
3030                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3031                  * IMM's larger than 32bits.
3032                  */
3033                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3034                 card_reg = ins->dreg;
3035
3036                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3037                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3038         } else {
3039                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3040                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3041         }
3042
3043         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3044 }
3045
3046 static gboolean
3047 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3048 {
3049         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3050         unsigned need_wb = 0;
3051
3052         if (align == 0)
3053                 align = 4;
3054
3055         /*types with references can't have alignment smaller than sizeof(void*) */
3056         if (align < SIZEOF_VOID_P)
3057                 return FALSE;
3058
3059         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3060         if (size > 32 * SIZEOF_VOID_P)
3061                 return FALSE;
3062
3063         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3064
3065         /* We don't unroll more than 5 stores to avoid code bloat. */
3066         if (size > 5 * SIZEOF_VOID_P) {
3067                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3068                 size += (SIZEOF_VOID_P - 1);
3069                 size &= ~(SIZEOF_VOID_P - 1);
3070
3071                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3072                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3073                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3074                 return TRUE;
3075         }
3076
3077         destreg = iargs [0]->dreg;
3078         srcreg = iargs [1]->dreg;
3079         offset = 0;
3080
3081         dest_ptr_reg = alloc_preg (cfg);
3082         tmp_reg = alloc_preg (cfg);
3083
3084         /*tmp = dreg*/
3085         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3086
3087         while (size >= SIZEOF_VOID_P) {
3088                 MonoInst *load_inst;
3089                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3090                 load_inst->dreg = tmp_reg;
3091                 load_inst->inst_basereg = srcreg;
3092                 load_inst->inst_offset = offset;
3093                 MONO_ADD_INS (cfg->cbb, load_inst);
3094
3095                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3096
3097                 if (need_wb & 0x1)
3098                         emit_write_barrier (cfg, iargs [0], load_inst);
3099
3100                 offset += SIZEOF_VOID_P;
3101                 size -= SIZEOF_VOID_P;
3102                 need_wb >>= 1;
3103
3104                 /*tmp += sizeof (void*)*/
3105                 if (size >= SIZEOF_VOID_P) {
3106                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3107                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3108                 }
3109         }
3110
3111         /* Those cannot be references since size < sizeof (void*) */
3112         while (size >= 4) {
3113                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3114                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3115                 offset += 4;
3116                 size -= 4;
3117         }
3118
3119         while (size >= 2) {
3120                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3121                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3122                 offset += 2;
3123                 size -= 2;
3124         }
3125
3126         while (size >= 1) {
3127                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3128                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3129                 offset += 1;
3130                 size -= 1;
3131         }
3132
3133         return TRUE;
3134 }
3135
3136 /*
3137  * Emit code to copy a valuetype of type @klass whose address is stored in
3138  * @src->dreg to memory whose address is stored at @dest->dreg.
3139  */
3140 void
3141 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3142 {
3143         MonoInst *iargs [4];
3144         int n;
3145         guint32 align = 0;
3146         MonoMethod *memcpy_method;
3147         MonoInst *size_ins = NULL;
3148         MonoInst *memcpy_ins = NULL;
3149
3150         g_assert (klass);
3151         if (cfg->gshared)
3152                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3153
3154         /*
3155          * This check breaks with spilled vars... need to handle it during verification anyway.
3156          * g_assert (klass && klass == src->klass && klass == dest->klass);
3157          */
3158
3159         if (mini_is_gsharedvt_klass (klass)) {
3160                 g_assert (!native);
3161                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3162                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3163         }
3164
3165         if (native)
3166                 n = mono_class_native_size (klass, &align);
3167         else
3168                 n = mono_class_value_size (klass, &align);
3169
3170         /* if native is true there should be no references in the struct */
3171         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3172                 /* Avoid barriers when storing to the stack */
3173                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3174                           (dest->opcode == OP_LDADDR))) {
3175                         int context_used;
3176
3177                         iargs [0] = dest;
3178                         iargs [1] = src;
3179
3180                         context_used = mini_class_check_context_used (cfg, klass);
3181
3182                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3183                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3184                                 return;
3185                         } else if (context_used) {
3186                                 iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3187                         }  else {
3188                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3189                                 if (!cfg->compile_aot)
3190                                         mono_class_compute_gc_descriptor (klass);
3191                         }
3192
3193                         if (size_ins)
3194                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3195                         else
3196                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3197                         return;
3198                 }
3199         }
3200
3201         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3202                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3203                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3204         } else {
3205                 iargs [0] = dest;
3206                 iargs [1] = src;
3207                 if (size_ins)
3208                         iargs [2] = size_ins;
3209                 else
3210                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3211                 
3212                 memcpy_method = get_memcpy_method ();
3213                 if (memcpy_ins)
3214                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3215                 else
3216                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3217         }
3218 }
3219
3220 static MonoMethod*
3221 get_memset_method (void)
3222 {
3223         static MonoMethod *memset_method = NULL;
3224         if (!memset_method) {
3225                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3226                 if (!memset_method)
3227                         g_error ("Old corlib found. Install a new one");
3228         }
3229         return memset_method;
3230 }
3231
3232 void
3233 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3234 {
3235         MonoInst *iargs [3];
3236         int n;
3237         guint32 align;
3238         MonoMethod *memset_method;
3239         MonoInst *size_ins = NULL;
3240         MonoInst *bzero_ins = NULL;
3241         static MonoMethod *bzero_method;
3242
3243         /* FIXME: Optimize this for the case when dest is an LDADDR */
3244         mono_class_init (klass);
3245         if (mini_is_gsharedvt_klass (klass)) {
3246                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3247                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3248                 if (!bzero_method)
3249                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3250                 g_assert (bzero_method);
3251                 iargs [0] = dest;
3252                 iargs [1] = size_ins;
3253                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3254                 return;
3255         }
3256
3257         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3258
3259         n = mono_class_value_size (klass, &align);
3260
3261         if (n <= sizeof (gpointer) * 8) {
3262                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3263         }
3264         else {
3265                 memset_method = get_memset_method ();
3266                 iargs [0] = dest;
3267                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3268                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3269                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3270         }
3271 }
3272
3273 /*
3274  * emit_get_rgctx:
3275  *
3276  *   Emit IR to return either the this pointer for instance method,
3277  * or the mrgctx for static methods.
3278  */
3279 static MonoInst*
3280 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3281 {
3282         MonoInst *this_ins = NULL;
3283
3284         g_assert (cfg->gshared);
3285
3286         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3287                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3288                 !method->klass->valuetype)
3289                 EMIT_NEW_VARLOAD (cfg, this_ins, cfg->this_arg, &mono_defaults.object_class->byval_arg);
3290
3291         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3292                 MonoInst *mrgctx_loc, *mrgctx_var;
3293
3294                 g_assert (!this_ins);
3295                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3296
3297                 mrgctx_loc = mono_get_vtable_var (cfg);
3298                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3299
3300                 return mrgctx_var;
3301         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3302                 MonoInst *vtable_loc, *vtable_var;
3303
3304                 g_assert (!this_ins);
3305
3306                 vtable_loc = mono_get_vtable_var (cfg);
3307                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3308
3309                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3310                         MonoInst *mrgctx_var = vtable_var;
3311                         int vtable_reg;
3312
3313                         vtable_reg = alloc_preg (cfg);
3314                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3315                         vtable_var->type = STACK_PTR;
3316                 }
3317
3318                 return vtable_var;
3319         } else {
3320                 MonoInst *ins;
3321                 int vtable_reg;
3322         
3323                 vtable_reg = alloc_preg (cfg);
3324                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3325                 return ins;
3326         }
3327 }
3328
3329 static MonoJumpInfoRgctxEntry *
3330 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3331 {
3332         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3333         res->method = method;
3334         res->in_mrgctx = in_mrgctx;
3335         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3336         res->data->type = patch_type;
3337         res->data->data.target = patch_data;
3338         res->info_type = info_type;
3339
3340         return res;
3341 }
3342
3343 static inline MonoInst*
3344 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3345 {
3346         MonoInst *args [16];
3347         MonoInst *call;
3348
3349         // FIXME: No fastpath since the slot is not a compile time constant
3350         args [0] = rgctx;
3351         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3352         if (entry->in_mrgctx)
3353                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3354         else
3355                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3356         return call;
3357 #if 0
3358         /*
3359          * FIXME: This can be called during decompose, which is a problem since it creates
3360          * new bblocks.
3361          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3362          */
3363         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3364         gboolean mrgctx;
3365         MonoBasicBlock *is_null_bb, *end_bb;
3366         MonoInst *res, *ins, *call;
3367         MonoInst *args[16];
3368
3369         slot = mini_get_rgctx_entry_slot (entry);
3370
3371         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3372         index = MONO_RGCTX_SLOT_INDEX (slot);
3373         if (mrgctx)
3374                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3375         for (depth = 0; ; ++depth) {
3376                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3377
3378                 if (index < size - 1)
3379                         break;
3380                 index -= size - 1;
3381         }
3382
3383         NEW_BBLOCK (cfg, end_bb);
3384         NEW_BBLOCK (cfg, is_null_bb);
3385
3386         if (mrgctx) {
3387                 rgctx_reg = rgctx->dreg;
3388         } else {
3389                 rgctx_reg = alloc_preg (cfg);
3390
3391                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3392                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3393                 NEW_BBLOCK (cfg, is_null_bb);
3394
3395                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3396                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3397         }
3398
3399         for (i = 0; i < depth; ++i) {
3400                 int array_reg = alloc_preg (cfg);
3401
3402                 /* load ptr to next array */
3403                 if (mrgctx && i == 0)
3404                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3405                 else
3406                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3407                 rgctx_reg = array_reg;
3408                 /* is the ptr null? */
3409                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3410                 /* if yes, jump to actual trampoline */
3411                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3412         }
3413
3414         /* fetch slot */
3415         val_reg = alloc_preg (cfg);
3416         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3417         /* is the slot null? */
3418         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3419         /* if yes, jump to actual trampoline */
3420         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3421
3422         /* Fastpath */
3423         res_reg = alloc_preg (cfg);
3424         MONO_INST_NEW (cfg, ins, OP_MOVE);
3425         ins->dreg = res_reg;
3426         ins->sreg1 = val_reg;
3427         MONO_ADD_INS (cfg->cbb, ins);
3428         res = ins;
3429         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3430
3431         /* Slowpath */
3432         MONO_START_BB (cfg, is_null_bb);
3433         args [0] = rgctx;
3434         EMIT_NEW_ICONST (cfg, args [1], index);
3435         if (mrgctx)
3436                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3437         else
3438                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3439         MONO_INST_NEW (cfg, ins, OP_MOVE);
3440         ins->dreg = res_reg;
3441         ins->sreg1 = call->dreg;
3442         MONO_ADD_INS (cfg->cbb, ins);
3443         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3444
3445         MONO_START_BB (cfg, end_bb);
3446
3447         return res;
3448 #endif
3449 }
3450
3451 /*
3452  * emit_rgctx_fetch:
3453  *
3454  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3455  * given by RGCTX.
3456  */
3457 static inline MonoInst*
3458 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3459 {
3460         if (cfg->llvm_only)
3461                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3462         else
3463                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3464 }
3465
3466 MonoInst*
3467 mini_emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3468                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3469 {
3470         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_CLASS, klass, rgctx_type);
3471         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3472
3473         return emit_rgctx_fetch (cfg, rgctx, entry);
3474 }
3475
3476 static MonoInst*
3477 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3478                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3479 {
3480         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_SIGNATURE, sig, rgctx_type);
3481         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3482
3483         return emit_rgctx_fetch (cfg, rgctx, entry);
3484 }
3485
3486 static MonoInst*
3487 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3488                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3489 {
3490         MonoJumpInfoGSharedVtCall *call_info;
3491         MonoJumpInfoRgctxEntry *entry;
3492         MonoInst *rgctx;
3493
3494         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3495         call_info->sig = sig;
3496         call_info->method = cmethod;
3497
3498         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_CALL, call_info, rgctx_type);
3499         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3500
3501         return emit_rgctx_fetch (cfg, rgctx, entry);
3502 }
3503
3504 /*
3505  * emit_get_rgctx_virt_method:
3506  *
3507  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3508  */
3509 static MonoInst*
3510 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3511                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3512 {
3513         MonoJumpInfoVirtMethod *info;
3514         MonoJumpInfoRgctxEntry *entry;
3515         MonoInst *rgctx;
3516
3517         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3518         info->klass = klass;
3519         info->method = virt_method;
3520
3521         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_VIRT_METHOD, info, rgctx_type);
3522         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3523
3524         return emit_rgctx_fetch (cfg, rgctx, entry);
3525 }
3526
3527 static MonoInst*
3528 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3529                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3530 {
3531         MonoJumpInfoRgctxEntry *entry;
3532         MonoInst *rgctx;
3533
3534         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_METHOD, info, MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO);
3535         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3536
3537         return emit_rgctx_fetch (cfg, rgctx, entry);
3538 }
3539
3540 /*
3541  * emit_get_rgctx_method:
3542  *
3543  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3544  * normal constants, else emit a load from the rgctx.
3545  */
3546 static MonoInst*
3547 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3548                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3549 {
3550         if (!context_used) {
3551                 MonoInst *ins;
3552
3553                 switch (rgctx_type) {
3554                 case MONO_RGCTX_INFO_METHOD:
3555                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3556                         return ins;
3557                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3558                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3559                         return ins;
3560                 default:
3561                         g_assert_not_reached ();
3562                 }
3563         } else {
3564                 MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
3565                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3566
3567                 return emit_rgctx_fetch (cfg, rgctx, entry);
3568         }
3569 }
3570
3571 static MonoInst*
3572 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3573                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3574 {
3575         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_FIELD, field, rgctx_type);
3576         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3577
3578         return emit_rgctx_fetch (cfg, rgctx, entry);
3579 }
3580
3581 static int
3582 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3583 {
3584         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3585         MonoRuntimeGenericContextInfoTemplate *template_;
3586         int i, idx;
3587
3588         g_assert (info);
3589
3590         for (i = 0; i < info->num_entries; ++i) {
3591                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3592
3593                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3594                         return i;
3595         }
3596
3597         if (info->num_entries == info->count_entries) {
3598                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3599                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3600
3601                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3602
3603                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3604                 info->entries = new_entries;
3605                 info->count_entries = new_count_entries;
3606         }
3607
3608         idx = info->num_entries;
3609         template_ = &info->entries [idx];
3610         template_->info_type = rgctx_type;
3611         template_->data = data;
3612
3613         info->num_entries ++;
3614
3615         return idx;
3616 }
3617
3618 /*
3619  * emit_get_gsharedvt_info:
3620  *
3621  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3622  */
3623 static MonoInst*
3624 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3625 {
3626         MonoInst *ins;
3627         int idx, dreg;
3628
3629         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3630         /* Load info->entries [idx] */
3631         dreg = alloc_preg (cfg);
3632         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3633
3634         return ins;
3635 }
3636
3637 static MonoInst*
3638 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3639 {
3640         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3641 }
3642
3643 /*
3644  * On return the caller must check @klass for load errors.
3645  */
3646 static void
3647 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3648 {
3649         MonoInst *vtable_arg;
3650         int context_used;
3651
3652         context_used = mini_class_check_context_used (cfg, klass);
3653
3654         if (context_used) {
3655                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
3656                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3657         } else {
3658                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3659
3660                 if (!vtable)
3661                         return;
3662                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3663         }
3664
3665         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3666                 MonoInst *ins;
3667
3668                 /*
3669                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3670                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3671                  */
3672                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3673                 ins->sreg1 = vtable_arg->dreg;
3674                 MONO_ADD_INS (cfg->cbb, ins);
3675         } else {
3676                 int inited_reg;
3677                 MonoBasicBlock *inited_bb;
3678                 MonoInst *args [16];
3679
3680                 inited_reg = alloc_ireg (cfg);
3681
3682                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, inited_reg, vtable_arg->dreg, MONO_STRUCT_OFFSET (MonoVTable, initialized));
3683
3684                 NEW_BBLOCK (cfg, inited_bb);
3685
3686                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3687                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3688
3689                 args [0] = vtable_arg;
3690                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3691
3692                 MONO_START_BB (cfg, inited_bb);
3693         }
3694 }
3695
3696 static void
3697 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3698 {
3699         MonoInst *ins;
3700
3701         if (cfg->gen_seq_points && cfg->method == method) {
3702                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3703                 if (nonempty_stack)
3704                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3705                 MONO_ADD_INS (cfg->cbb, ins);
3706         }
3707 }
3708
3709 void
3710 mini_save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3711 {
3712         if (mini_get_debug_options ()->better_cast_details) {
3713                 int vtable_reg = alloc_preg (cfg);
3714                 int klass_reg = alloc_preg (cfg);
3715                 MonoBasicBlock *is_null_bb = NULL;
3716                 MonoInst *tls_get;
3717                 int to_klass_reg, context_used;
3718
3719                 if (null_check) {
3720                         NEW_BBLOCK (cfg, is_null_bb);
3721
3722                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3723                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3724                 }
3725
3726                 tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
3727                 if (!tls_get) {
3728                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3729                         exit (1);
3730                 }
3731
3732                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3733                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3734
3735                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3736
3737                 context_used = mini_class_check_context_used (cfg, klass);
3738                 if (context_used) {
3739                         MonoInst *class_ins;
3740
3741                         class_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3742                         to_klass_reg = class_ins->dreg;
3743                 } else {
3744                         to_klass_reg = alloc_preg (cfg);
3745                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3746                 }
3747                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3748
3749                 if (null_check)
3750                         MONO_START_BB (cfg, is_null_bb);
3751         }
3752 }
3753
3754 void
3755 mini_reset_cast_details (MonoCompile *cfg)
3756 {
3757         /* Reset the variables holding the cast details */
3758         if (mini_get_debug_options ()->better_cast_details) {
3759                 MonoInst *tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
3760                 /* It is enough to reset the from field */
3761                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3762         }
3763 }
3764
3765 /*
3766  * On return the caller must check @array_class for load errors
3767  */
3768 static void
3769 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3770 {
3771         int vtable_reg = alloc_preg (cfg);
3772         int context_used;
3773
3774         context_used = mini_class_check_context_used (cfg, array_class);
3775
3776         mini_save_cast_details (cfg, array_class, obj->dreg, FALSE);
3777
3778         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3779
3780         if (cfg->opt & MONO_OPT_SHARED) {
3781                 int class_reg = alloc_preg (cfg);
3782                 MonoInst *ins;
3783
3784                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3785                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3786                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3787         } else if (context_used) {
3788                 MonoInst *vtable_ins;
3789
3790                 vtable_ins = mini_emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3791                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3792         } else {
3793                 if (cfg->compile_aot) {
3794                         int vt_reg;
3795                         MonoVTable *vtable;
3796
3797                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3798                                 return;
3799                         vt_reg = alloc_preg (cfg);
3800                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3801                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3802                 } else {
3803                         MonoVTable *vtable;
3804                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3805                                 return;
3806                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3807                 }
3808         }
3809         
3810         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3811
3812         mini_reset_cast_details (cfg);
3813 }
3814
3815 /**
3816  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3817  * generic code is generated.
3818  */
3819 static MonoInst*
3820 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3821 {
3822         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3823
3824         if (context_used) {
3825                 MonoInst *rgctx, *addr;
3826
3827                 /* FIXME: What if the class is shared?  We might not
3828                    have to get the address of the method from the
3829                    RGCTX. */
3830                 addr = emit_get_rgctx_method (cfg, context_used, method,
3831                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3832                 if (cfg->llvm_only) {
3833                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
3834                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
3835                 } else {
3836                         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3837
3838                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3839                 }
3840         } else {
3841                 gboolean pass_vtable, pass_mrgctx;
3842                 MonoInst *rgctx_arg = NULL;
3843
3844                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3845                 g_assert (!pass_mrgctx);
3846
3847                 if (pass_vtable) {
3848                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3849
3850                         g_assert (vtable);
3851                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3852                 }
3853
3854                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3855         }
3856 }
3857
3858 static MonoInst*
3859 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3860 {
3861         MonoInst *add;
3862         int obj_reg;
3863         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3864         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3865         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3866         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3867
3868         obj_reg = sp [0]->dreg;
3869         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3870         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3871
3872         /* FIXME: generics */
3873         g_assert (klass->rank == 0);
3874                         
3875         // Check rank == 0
3876         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3877         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3878
3879         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3880         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3881
3882         if (context_used) {
3883                 MonoInst *element_class;
3884
3885                 /* This assertion is from the unboxcast insn */
3886                 g_assert (klass->rank == 0);
3887
3888                 element_class = mini_emit_get_rgctx_klass (cfg, context_used,
3889                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
3890
3891                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3892                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3893         } else {
3894                 mini_save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
3895                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3896                 mini_reset_cast_details (cfg);
3897         }
3898
3899         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3900         MONO_ADD_INS (cfg->cbb, add);
3901         add->type = STACK_MP;
3902         add->klass = klass;
3903
3904         return add;
3905 }
3906
3907 static MonoInst*
3908 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
3909 {
3910         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3911         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3912         MonoInst *ins;
3913         int dreg, addr_reg;
3914
3915         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3916
3917         /* obj */
3918         args [0] = obj;
3919
3920         /* klass */
3921         args [1] = klass_inst;
3922
3923         /* CASTCLASS */
3924         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3925
3926         NEW_BBLOCK (cfg, is_ref_bb);
3927         NEW_BBLOCK (cfg, is_nullable_bb);
3928         NEW_BBLOCK (cfg, end_bb);
3929         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3930         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
3931         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3932
3933         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
3934         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3935
3936         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3937         addr_reg = alloc_dreg (cfg, STACK_MP);
3938
3939         /* Non-ref case */
3940         /* UNBOX */
3941         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3942         MONO_ADD_INS (cfg->cbb, addr);
3943
3944         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3945
3946         /* Ref case */
3947         MONO_START_BB (cfg, is_ref_bb);
3948
3949         /* Save the ref to a temporary */
3950         dreg = alloc_ireg (cfg);
3951         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3952         addr->dreg = addr_reg;
3953         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3954         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3955
3956         /* Nullable case */
3957         MONO_START_BB (cfg, is_nullable_bb);
3958
3959         {
3960                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3961                 MonoInst *unbox_call;
3962                 MonoMethodSignature *unbox_sig;
3963
3964                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3965                 unbox_sig->ret = &klass->byval_arg;
3966                 unbox_sig->param_count = 1;
3967                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3968
3969                 if (cfg->llvm_only)
3970                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
3971                 else
3972                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3973
3974                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3975                 addr->dreg = addr_reg;
3976         }
3977
3978         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3979
3980         /* End */
3981         MONO_START_BB (cfg, end_bb);
3982
3983         /* LDOBJ */
3984         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3985
3986         return ins;
3987 }
3988
3989 /*
3990  * Returns NULL and set the cfg exception on error.
3991  */
3992 static MonoInst*
3993 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3994 {
3995         MonoInst *iargs [2];
3996         void *alloc_ftn;
3997
3998         if (context_used) {
3999                 MonoInst *data;
4000                 MonoRgctxInfoType rgctx_info;
4001                 MonoInst *iargs [2];
4002                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4003
4004                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4005
4006                 if (cfg->opt & MONO_OPT_SHARED)
4007                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4008                 else
4009                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4010                 data = mini_emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4011
4012                 if (cfg->opt & MONO_OPT_SHARED) {
4013                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4014                         iargs [1] = data;
4015                         alloc_ftn = ves_icall_object_new;
4016                 } else {
4017                         iargs [0] = data;
4018                         alloc_ftn = ves_icall_object_new_specific;
4019                 }
4020
4021                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4022                         if (known_instance_size) {
4023                                 int size = mono_class_instance_size (klass);
4024                                 if (size < sizeof (MonoObject))
4025                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4026
4027                                 EMIT_NEW_ICONST (cfg, iargs [1], size);
4028                         }
4029                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4030                 }
4031
4032                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4033         }
4034
4035         if (cfg->opt & MONO_OPT_SHARED) {
4036                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4037                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4038
4039                 alloc_ftn = ves_icall_object_new;
4040         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !mono_class_is_ginst (klass)) {
4041                 /* This happens often in argument checking code, eg. throw new FooException... */
4042                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4043                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4044                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4045         } else {
4046                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4047                 MonoMethod *managed_alloc = NULL;
4048                 gboolean pass_lw;
4049
4050                 if (!vtable) {
4051                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4052                         cfg->exception_ptr = klass;
4053                         return NULL;
4054                 }
4055
4056                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4057
4058                 if (managed_alloc) {
4059                         int size = mono_class_instance_size (klass);
4060                         if (size < sizeof (MonoObject))
4061                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4062
4063                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4064                         EMIT_NEW_ICONST (cfg, iargs [1], size);
4065                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4066                 }
4067                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4068                 if (pass_lw) {
4069                         guint32 lw = vtable->klass->instance_size;
4070                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4071                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4072                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4073                 }
4074                 else {
4075                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4076                 }
4077         }
4078
4079         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4080 }
4081         
4082 /*
4083  * Returns NULL and set the cfg exception on error.
4084  */     
4085 static MonoInst*
4086 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4087 {
4088         MonoInst *alloc, *ins;
4089
4090         if (mono_class_is_nullable (klass)) {
4091                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4092
4093                 if (context_used) {
4094                         if (cfg->llvm_only && cfg->gsharedvt) {
4095                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4096                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4097                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4098                         } else {
4099                                 /* FIXME: What if the class is shared?  We might not
4100                                    have to get the method address from the RGCTX. */
4101                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4102                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4103                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
4104
4105                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4106                         }
4107                 } else {
4108                         gboolean pass_vtable, pass_mrgctx;
4109                         MonoInst *rgctx_arg = NULL;
4110
4111                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4112                         g_assert (!pass_mrgctx);
4113
4114                         if (pass_vtable) {
4115                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4116
4117                                 g_assert (vtable);
4118                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4119                         }
4120
4121                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4122                 }
4123         }
4124
4125         if (mini_is_gsharedvt_klass (klass)) {
4126                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4127                 MonoInst *res, *is_ref, *src_var, *addr;
4128                 int dreg;
4129
4130                 dreg = alloc_ireg (cfg);
4131
4132                 NEW_BBLOCK (cfg, is_ref_bb);
4133                 NEW_BBLOCK (cfg, is_nullable_bb);
4134                 NEW_BBLOCK (cfg, end_bb);
4135                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4136                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4137                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4138
4139                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4140                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4141
4142                 /* Non-ref case */
4143                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4144                 if (!alloc)
4145                         return NULL;
4146                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4147                 ins->opcode = OP_STOREV_MEMBASE;
4148
4149                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4150                 res->type = STACK_OBJ;
4151                 res->klass = klass;
4152                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4153                 
4154                 /* Ref case */
4155                 MONO_START_BB (cfg, is_ref_bb);
4156
4157                 /* val is a vtype, so has to load the value manually */
4158                 src_var = get_vreg_to_inst (cfg, val->dreg);
4159                 if (!src_var)
4160                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4161                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4162                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4163                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4164
4165                 /* Nullable case */
4166                 MONO_START_BB (cfg, is_nullable_bb);
4167
4168                 {
4169                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4170                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4171                         MonoInst *box_call;
4172                         MonoMethodSignature *box_sig;
4173
4174                         /*
4175                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4176                          * construct that method at JIT time, so have to do things by hand.
4177                          */
4178                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4179                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4180                         box_sig->param_count = 1;
4181                         box_sig->params [0] = &klass->byval_arg;
4182
4183                         if (cfg->llvm_only)
4184                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4185                         else
4186                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4187                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4188                         res->type = STACK_OBJ;
4189                         res->klass = klass;
4190                 }
4191
4192                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4193
4194                 MONO_START_BB (cfg, end_bb);
4195
4196                 return res;
4197         } else {
4198                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4199                 if (!alloc)
4200                         return NULL;
4201
4202                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4203                 return alloc;
4204         }
4205 }
4206
4207 static GHashTable* direct_icall_type_hash;
4208
4209 static gboolean
4210 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4211 {
4212         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4213         if (!direct_icalls_enabled (cfg))
4214                 return FALSE;
4215
4216         /*
4217          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4218          * Whitelist a few icalls for now.
4219          */
4220         if (!direct_icall_type_hash) {
4221                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4222
4223                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4224                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4225                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4226                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4227                 mono_memory_barrier ();
4228                 direct_icall_type_hash = h;
4229         }
4230
4231         if (cmethod->klass == mono_defaults.math_class)
4232                 return TRUE;
4233         /* No locking needed */
4234         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4235                 return TRUE;
4236         return FALSE;
4237 }
4238
4239 static gboolean
4240 method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
4241 {
4242         if (cmethod->klass == mono_defaults.systemtype_class) {
4243                 if (!strcmp (cmethod->name, "GetType"))
4244                         return TRUE;
4245         }
4246         return FALSE;
4247 }
4248
4249 static G_GNUC_UNUSED MonoInst*
4250 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4251 {
4252         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4253         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4254         gboolean is_i4;
4255
4256         switch (enum_type->type) {
4257         case MONO_TYPE_I8:
4258         case MONO_TYPE_U8:
4259 #if SIZEOF_REGISTER == 8
4260         case MONO_TYPE_I:
4261         case MONO_TYPE_U:
4262 #endif
4263                 is_i4 = FALSE;
4264                 break;
4265         default:
4266                 is_i4 = TRUE;
4267                 break;
4268         }
4269
4270         {
4271                 MonoInst *load, *and_, *cmp, *ceq;
4272                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4273                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4274                 int dest_reg = alloc_ireg (cfg);
4275
4276                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4277                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4278                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4279                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4280
4281                 ceq->type = STACK_I4;
4282
4283                 if (!is_i4) {
4284                         load = mono_decompose_opcode (cfg, load);
4285                         and_ = mono_decompose_opcode (cfg, and_);
4286                         cmp = mono_decompose_opcode (cfg, cmp);
4287                         ceq = mono_decompose_opcode (cfg, ceq);
4288                 }
4289
4290                 return ceq;
4291         }
4292 }
4293
4294 /*
4295  * Returns NULL and set the cfg exception on error.
4296  */
4297 static G_GNUC_UNUSED MonoInst*
4298 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
4299 {
4300         MonoInst *ptr;
4301         int dreg;
4302         gpointer trampoline;
4303         MonoInst *obj, *method_ins, *tramp_ins;
4304         MonoDomain *domain;
4305         guint8 **code_slot;
4306
4307         if (virtual_ && !cfg->llvm_only) {
4308                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4309                 g_assert (invoke);
4310
4311                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4312                         return NULL;
4313         }
4314
4315         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
4316         if (!obj)
4317                 return NULL;
4318
4319         /* Inline the contents of mono_delegate_ctor */
4320
4321         /* Set target field */
4322         /* Optimize away setting of NULL target */
4323         if (!MONO_INS_IS_PCONST_NULL (target)) {
4324                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4325                 if (cfg->gen_write_barriers) {
4326                         dreg = alloc_preg (cfg);
4327                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4328                         emit_write_barrier (cfg, ptr, target);
4329                 }
4330         }
4331
4332         /* Set method field */
4333         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4334         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4335
4336         /* 
4337          * To avoid looking up the compiled code belonging to the target method
4338          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4339          * store it, and we fill it after the method has been compiled.
4340          */
4341         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4342                 MonoInst *code_slot_ins;
4343
4344                 if (context_used) {
4345                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4346                 } else {
4347                         domain = mono_domain_get ();
4348                         mono_domain_lock (domain);
4349                         if (!domain_jit_info (domain)->method_code_hash)
4350                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4351                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4352                         if (!code_slot) {
4353                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
4354                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4355                         }
4356                         mono_domain_unlock (domain);
4357
4358                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4359                 }
4360                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4361         }
4362
4363         if (cfg->llvm_only) {
4364                 MonoInst *args [16];
4365
4366                 if (virtual_) {
4367                         args [0] = obj;
4368                         args [1] = target;
4369                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4370                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
4371                 } else {
4372                         args [0] = obj;
4373                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
4374                 }
4375
4376                 return obj;
4377         }
4378
4379         if (cfg->compile_aot) {
4380                 MonoDelegateClassMethodPair *del_tramp;
4381
4382                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4383                 del_tramp->klass = klass;
4384                 del_tramp->method = context_used ? NULL : method;
4385                 del_tramp->is_virtual = virtual_;
4386                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4387         } else {
4388                 if (virtual_)
4389                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4390                 else
4391                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4392                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4393         }
4394
4395         /* Set invoke_impl field */
4396         if (virtual_) {
4397                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4398         } else {
4399                 dreg = alloc_preg (cfg);
4400                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4401                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4402
4403                 dreg = alloc_preg (cfg);
4404                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4405                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4406         }
4407
4408         dreg = alloc_preg (cfg);
4409         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
4410         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
4411
4412         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4413
4414         return obj;
4415 }
4416
4417 static MonoInst*
4418 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4419 {
4420         MonoJitICallInfo *info;
4421
4422         /* Need to register the icall so it gets an icall wrapper */
4423         info = mono_get_array_new_va_icall (rank);
4424
4425         cfg->flags |= MONO_CFG_HAS_VARARGS;
4426
4427         /* mono_array_new_va () needs a vararg calling convention */
4428         cfg->exception_message = g_strdup ("array-new");
4429         cfg->disable_llvm = TRUE;
4430
4431         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4432         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4433 }
4434
4435 /*
4436  * handle_constrained_gsharedvt_call:
4437  *
4438  *   Handle constrained calls where the receiver is a gsharedvt type.
4439  * Return the instruction representing the call. Set the cfg exception on failure.
4440  */
4441 static MonoInst*
4442 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
4443                                                                    gboolean *ref_emit_widen)
4444 {
4445         MonoInst *ins = NULL;
4446         gboolean emit_widen = *ref_emit_widen;
4447
4448         /*
4449          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
4450          * This is hard to do with the current call code, since we would have to emit a branch and two different calls. So instead, we
4451          * pack the arguments into an array, and do the rest of the work in in an icall.
4452          */
4453         if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
4454                 (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mono_class_is_enum (mono_class_from_mono_type (fsig->ret)) || mini_is_gsharedvt_type (fsig->ret)) &&
4455                 (fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || fsig->params [0]->byref || mini_is_gsharedvt_type (fsig->params [0]))))) {
4456                 MonoInst *args [16];
4457
4458                 /*
4459                  * This case handles calls to
4460                  * - object:ToString()/Equals()/GetHashCode(),
4461                  * - System.IComparable<T>:CompareTo()
4462                  * - System.IEquatable<T>:Equals ()
4463                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
4464                  */
4465
4466                 args [0] = sp [0];
4467                 if (mono_method_check_context_used (cmethod))
4468                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
4469                 else
4470                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
4471                 args [2] = mini_emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
4472
4473                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
4474                 if (fsig->hasthis && fsig->param_count) {
4475                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
4476                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
4477                         ins->dreg = alloc_preg (cfg);
4478                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
4479                         MONO_ADD_INS (cfg->cbb, ins);
4480                         args [4] = ins;
4481
4482                         if (mini_is_gsharedvt_type (fsig->params [0])) {
4483                                 int addr_reg, deref_arg_reg;
4484
4485                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4486                                 deref_arg_reg = alloc_preg (cfg);
4487                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
4488                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
4489
4490                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
4491                                 addr_reg = ins->dreg;
4492                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
4493                         } else {
4494                                 EMIT_NEW_ICONST (cfg, args [3], 0);
4495                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
4496                         }
4497                 } else {
4498                         EMIT_NEW_ICONST (cfg, args [3], 0);
4499                         EMIT_NEW_ICONST (cfg, args [4], 0);
4500                 }
4501                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
4502                 emit_widen = FALSE;
4503
4504                 if (mini_is_gsharedvt_type (fsig->ret)) {
4505                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
4506                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mono_class_is_enum (mono_class_from_mono_type (fsig->ret))) {
4507                         MonoInst *add;
4508
4509                         /* Unbox */
4510                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
4511                         MONO_ADD_INS (cfg->cbb, add);
4512                         /* Load value */
4513                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
4514                         MONO_ADD_INS (cfg->cbb, ins);
4515                         /* ins represents the call result */
4516                 }
4517         } else {
4518                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
4519         }
4520
4521         *ref_emit_widen = emit_widen;
4522
4523         return ins;
4524
4525  exception_exit:
4526         return NULL;
4527 }
4528
4529 static void
4530 mono_emit_load_got_addr (MonoCompile *cfg)
4531 {
4532         MonoInst *getaddr, *dummy_use;
4533
4534         if (!cfg->got_var || cfg->got_var_allocated)
4535                 return;
4536
4537         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4538         getaddr->cil_code = cfg->header->code;
4539         getaddr->dreg = cfg->got_var->dreg;
4540
4541         /* Add it to the start of the first bblock */
4542         if (cfg->bb_entry->code) {
4543                 getaddr->next = cfg->bb_entry->code;
4544                 cfg->bb_entry->code = getaddr;
4545         }
4546         else
4547                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4548
4549         cfg->got_var_allocated = TRUE;
4550
4551         /* 
4552          * Add a dummy use to keep the got_var alive, since real uses might
4553          * only be generated by the back ends.
4554          * Add it to end_bblock, so the variable's lifetime covers the whole
4555          * method.
4556          * It would be better to make the usage of the got var explicit in all
4557          * cases when the backend needs it (i.e. calls, throw etc.), so this
4558          * wouldn't be needed.
4559          */
4560         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4561         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4562 }
4563
4564 static int inline_limit;
4565 static gboolean inline_limit_inited;
4566
4567 static gboolean
4568 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4569 {
4570         MonoMethodHeaderSummary header;
4571         MonoVTable *vtable;
4572 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4573         MonoMethodSignature *sig = mono_method_signature (method);
4574         int i;
4575 #endif
4576
4577         if (cfg->disable_inline)
4578                 return FALSE;
4579         if (cfg->gsharedvt)
4580                 return FALSE;
4581
4582         if (cfg->inline_depth > 10)
4583                 return FALSE;
4584
4585         if (!mono_method_get_header_summary (method, &header))
4586                 return FALSE;
4587
4588         /*runtime, icall and pinvoke are checked by summary call*/
4589         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4590             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4591             (mono_class_is_marshalbyref (method->klass)) ||
4592             header.has_clauses)
4593                 return FALSE;
4594
4595         /* also consider num_locals? */
4596         /* Do the size check early to avoid creating vtables */
4597         if (!inline_limit_inited) {
4598                 if (g_getenv ("MONO_INLINELIMIT"))
4599                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4600                 else
4601                         inline_limit = INLINE_LENGTH_LIMIT;
4602                 inline_limit_inited = TRUE;
4603         }
4604         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4605                 return FALSE;
4606
4607         /*
4608          * if we can initialize the class of the method right away, we do,
4609          * otherwise we don't allow inlining if the class needs initialization,
4610          * since it would mean inserting a call to mono_runtime_class_init()
4611          * inside the inlined code
4612          */
4613         if (cfg->gshared && method->klass->has_cctor && mini_class_check_context_used (cfg, method->klass))
4614                 return FALSE;
4615
4616         if (!(cfg->opt & MONO_OPT_SHARED)) {
4617                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4618                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4619                         if (method->klass->has_cctor) {
4620                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4621                                 if (!vtable)
4622                                         return FALSE;
4623                                 if (!cfg->compile_aot) {
4624                                         MonoError error;
4625                                         if (!mono_runtime_class_init_full (vtable, &error)) {
4626                                                 mono_error_cleanup (&error);
4627                                                 return FALSE;
4628                                         }
4629                                 }
4630                         }
4631                 } else if (mono_class_is_before_field_init (method->klass)) {
4632                         if (cfg->run_cctors && method->klass->has_cctor) {
4633                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4634                                 if (!method->klass->runtime_info)
4635                                         /* No vtable created yet */
4636                                         return FALSE;
4637                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4638                                 if (!vtable)
4639                                         return FALSE;
4640                                 /* This makes so that inline cannot trigger */
4641                                 /* .cctors: too many apps depend on them */
4642                                 /* running with a specific order... */
4643                                 if (! vtable->initialized)
4644                                         return FALSE;
4645                                 MonoError error;
4646                                 if (!mono_runtime_class_init_full (vtable, &error)) {
4647                                         mono_error_cleanup (&error);
4648                                         return FALSE;
4649                                 }
4650                         }
4651                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4652                         if (!method->klass->runtime_info)
4653                                 /* No vtable created yet */
4654                                 return FALSE;
4655                         vtable = mono_class_vtable (cfg->domain, method->klass);
4656                         if (!vtable)
4657                                 return FALSE;
4658                         if (!vtable->initialized)
4659                                 return FALSE;
4660                 }
4661         } else {
4662                 /* 
4663                  * If we're compiling for shared code
4664                  * the cctor will need to be run at aot method load time, for example,
4665                  * or at the end of the compilation of the inlining method.
4666                  */
4667                 if (mono_class_needs_cctor_run (method->klass, NULL) && !mono_class_is_before_field_init (method->klass))
4668                         return FALSE;
4669         }
4670
4671 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4672         if (mono_arch_is_soft_float ()) {
4673                 /* FIXME: */
4674                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4675                         return FALSE;
4676                 for (i = 0; i < sig->param_count; ++i)
4677                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4678                                 return FALSE;
4679         }
4680 #endif
4681
4682         if (g_list_find (cfg->dont_inline, method))
4683                 return FALSE;
4684
4685         return TRUE;
4686 }
4687
4688 static gboolean
4689 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4690 {
4691         if (!cfg->compile_aot) {
4692                 g_assert (vtable);
4693                 if (vtable->initialized)
4694                         return FALSE;
4695         }
4696
4697         if (mono_class_is_before_field_init (klass)) {
4698                 if (cfg->method == method)
4699                         return FALSE;
4700         }
4701
4702         if (!mono_class_needs_cctor_run (klass, method))
4703                 return FALSE;
4704
4705         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4706                 /* The initialization is already done before the method is called */
4707                 return FALSE;
4708
4709         return TRUE;
4710 }
4711
4712 MonoInst*
4713 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4714 {
4715         MonoInst *ins;
4716         guint32 size;
4717         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4718         int context_used;
4719
4720         if (mini_is_gsharedvt_variable_klass (klass)) {
4721                 size = -1;
4722         } else {
4723                 mono_class_init (klass);
4724                 size = mono_class_array_element_size (klass);
4725         }
4726
4727         mult_reg = alloc_preg (cfg);
4728         array_reg = arr->dreg;
4729         index_reg = index->dreg;
4730
4731 #if SIZEOF_REGISTER == 8
4732         /* The array reg is 64 bits but the index reg is only 32 */
4733         if (COMPILE_LLVM (cfg)) {
4734                 /* Not needed */
4735                 index2_reg = index_reg;
4736         } else {
4737                 index2_reg = alloc_preg (cfg);
4738                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4739         }
4740 #else
4741         if (index->type == STACK_I8) {
4742                 index2_reg = alloc_preg (cfg);
4743                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4744         } else {
4745                 index2_reg = index_reg;
4746         }
4747 #endif
4748
4749         if (bcheck)
4750                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4751
4752 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4753         if (size == 1 || size == 2 || size == 4 || size == 8) {
4754                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4755
4756                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
4757                 ins->klass = mono_class_get_element_class (klass);
4758                 ins->type = STACK_MP;
4759
4760                 return ins;
4761         }
4762 #endif          
4763
4764         add_reg = alloc_ireg_mp (cfg);
4765
4766         if (size == -1) {
4767                 MonoInst *rgctx_ins;
4768
4769                 /* gsharedvt */
4770                 g_assert (cfg->gshared);
4771                 context_used = mini_class_check_context_used (cfg, klass);
4772                 g_assert (context_used);
4773                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4774                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4775         } else {
4776                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4777         }
4778         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4779         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4780         ins->klass = mono_class_get_element_class (klass);
4781         ins->type = STACK_MP;
4782         MONO_ADD_INS (cfg->cbb, ins);
4783
4784         return ins;
4785 }
4786
4787 static MonoInst*
4788 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4789 {
4790         int bounds_reg = alloc_preg (cfg);
4791         int add_reg = alloc_ireg_mp (cfg);
4792         int mult_reg = alloc_preg (cfg);
4793         int mult2_reg = alloc_preg (cfg);
4794         int low1_reg = alloc_preg (cfg);
4795         int low2_reg = alloc_preg (cfg);
4796         int high1_reg = alloc_preg (cfg);
4797         int high2_reg = alloc_preg (cfg);
4798         int realidx1_reg = alloc_preg (cfg);
4799         int realidx2_reg = alloc_preg (cfg);
4800         int sum_reg = alloc_preg (cfg);
4801         int index1, index2, tmpreg;
4802         MonoInst *ins;
4803         guint32 size;
4804
4805         mono_class_init (klass);
4806         size = mono_class_array_element_size (klass);
4807
4808         index1 = index_ins1->dreg;
4809         index2 = index_ins2->dreg;
4810
4811 #if SIZEOF_REGISTER == 8
4812         /* The array reg is 64 bits but the index reg is only 32 */
4813         if (COMPILE_LLVM (cfg)) {
4814                 /* Not needed */
4815         } else {
4816                 tmpreg = alloc_preg (cfg);
4817                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4818                 index1 = tmpreg;
4819                 tmpreg = alloc_preg (cfg);
4820                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4821                 index2 = tmpreg;
4822         }
4823 #else
4824         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4825         tmpreg = -1;
4826 #endif
4827
4828         /* range checking */
4829         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4830                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4831
4832         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4833                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4834         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4835         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4836                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4837         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4838         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4839
4840         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4841                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4842         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4843         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4844                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4845         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4846         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4847
4848         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4849         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4850         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4851         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4852         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4853
4854         ins->type = STACK_MP;
4855         ins->klass = klass;
4856         MONO_ADD_INS (cfg->cbb, ins);
4857
4858         return ins;
4859 }
4860
4861 static MonoInst*
4862 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4863 {
4864         int rank;
4865         MonoInst *addr;
4866         MonoMethod *addr_method;
4867         int element_size;
4868         MonoClass *eclass = cmethod->klass->element_class;
4869
4870         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4871
4872         if (rank == 1)
4873                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
4874
4875         /* emit_ldelema_2 depends on OP_LMUL */
4876         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
4877                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
4878         }
4879
4880         if (mini_is_gsharedvt_variable_klass (eclass))
4881                 element_size = 0;
4882         else
4883                 element_size = mono_class_array_element_size (eclass);
4884         addr_method = mono_marshal_get_array_address (rank, element_size);
4885         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4886
4887         return addr;
4888 }
4889
4890 static MonoBreakPolicy
4891 always_insert_breakpoint (MonoMethod *method)
4892 {
4893         return MONO_BREAK_POLICY_ALWAYS;
4894 }
4895
4896 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4897
4898 /**
4899  * mono_set_break_policy:
4900  * policy_callback: the new callback function
4901  *
4902  * Allow embedders to decide wherther to actually obey breakpoint instructions
4903  * (both break IL instructions and Debugger.Break () method calls), for example
4904  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4905  * untrusted or semi-trusted code.
4906  *
4907  * @policy_callback will be called every time a break point instruction needs to
4908  * be inserted with the method argument being the method that calls Debugger.Break()
4909  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4910  * if it wants the breakpoint to not be effective in the given method.
4911  * #MONO_BREAK_POLICY_ALWAYS is the default.
4912  */
4913 void
4914 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4915 {
4916         if (policy_callback)
4917                 break_policy_func = policy_callback;
4918         else
4919                 break_policy_func = always_insert_breakpoint;
4920 }
4921
4922 static gboolean
4923 should_insert_brekpoint (MonoMethod *method) {
4924         switch (break_policy_func (method)) {
4925         case MONO_BREAK_POLICY_ALWAYS:
4926                 return TRUE;
4927         case MONO_BREAK_POLICY_NEVER:
4928                 return FALSE;
4929         case MONO_BREAK_POLICY_ON_DBG:
4930                 g_warning ("mdb no longer supported");
4931                 return FALSE;
4932         default:
4933                 g_warning ("Incorrect value returned from break policy callback");
4934                 return FALSE;
4935         }
4936 }
4937
4938 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4939 static MonoInst*
4940 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4941 {
4942         MonoInst *addr, *store, *load;
4943         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4944
4945         /* the bounds check is already done by the callers */
4946         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4947         if (is_set) {
4948                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4949                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4950                 if (mini_type_is_reference (&eklass->byval_arg))
4951                         emit_write_barrier (cfg, addr, load);
4952         } else {
4953                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4954                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4955         }
4956         return store;
4957 }
4958
4959
4960 static gboolean
4961 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4962 {
4963         return mini_type_is_reference (&klass->byval_arg);
4964 }
4965
4966 static MonoInst*
4967 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
4968 {
4969         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
4970                 !(MONO_INS_IS_PCONST_NULL (sp [2]))) {
4971                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
4972                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
4973                 MonoInst *iargs [3];
4974
4975                 if (!helper->slot)
4976                         mono_class_setup_vtable (obj_array);
4977                 g_assert (helper->slot);
4978
4979                 if (sp [0]->type != STACK_OBJ)
4980                         return NULL;
4981                 if (sp [2]->type != STACK_OBJ)
4982                         return NULL;
4983
4984                 iargs [2] = sp [2];
4985                 iargs [1] = sp [1];
4986                 iargs [0] = sp [0];
4987
4988                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
4989         } else {
4990                 MonoInst *ins;
4991
4992                 if (mini_is_gsharedvt_variable_klass (klass)) {
4993                         MonoInst *addr;
4994
4995                         // FIXME-VT: OP_ICONST optimization
4996                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
4997                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4998                         ins->opcode = OP_STOREV_MEMBASE;
4999                 } else if (sp [1]->opcode == OP_ICONST) {
5000                         int array_reg = sp [0]->dreg;
5001                         int index_reg = sp [1]->dreg;
5002                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5003
5004                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5005                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5006
5007                         if (safety_checks)
5008                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5009                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5010                 } else {
5011                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5012                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5013                         if (generic_class_is_reference_type (cfg, klass))
5014                                 emit_write_barrier (cfg, addr, sp [2]);
5015                 }
5016                 return ins;
5017         }
5018 }
5019
5020 static MonoInst*
5021 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5022 {
5023         MonoClass *eklass;
5024         
5025         if (is_set)
5026                 eklass = mono_class_from_mono_type (fsig->params [2]);
5027         else
5028                 eklass = mono_class_from_mono_type (fsig->ret);
5029
5030         if (is_set) {
5031                 return emit_array_store (cfg, eklass, args, FALSE);
5032         } else {
5033                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5034                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5035                 return ins;
5036         }
5037 }
5038
5039 static gboolean
5040 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5041 {
5042         uint32_t align;
5043         int param_size, return_size;
5044
5045         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5046         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5047
5048         if (cfg->verbose_level > 3)
5049                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5050
5051         //Don't allow mixing reference types with value types
5052         if (param_klass->valuetype != return_klass->valuetype) {
5053                 if (cfg->verbose_level > 3)
5054                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5055                 return FALSE;
5056         }
5057
5058         if (!param_klass->valuetype) {
5059                 if (cfg->verbose_level > 3)
5060                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5061                 return TRUE;
5062         }
5063
5064         //That are blitable
5065         if (param_klass->has_references || return_klass->has_references)
5066                 return FALSE;
5067
5068         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5069         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5070                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5071                         if (cfg->verbose_level > 3)
5072                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5073                 return FALSE;
5074         }
5075
5076         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5077                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5078                 if (cfg->verbose_level > 3)
5079                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5080                 return FALSE;
5081         }
5082
5083         param_size = mono_class_value_size (param_klass, &align);
5084         return_size = mono_class_value_size (return_klass, &align);
5085
5086         //We can do it if sizes match
5087         if (param_size == return_size) {
5088                 if (cfg->verbose_level > 3)
5089                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5090                 return TRUE;
5091         }
5092
5093         //No simple way to handle struct if sizes don't match
5094         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5095                 if (cfg->verbose_level > 3)
5096                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5097                 return FALSE;
5098         }
5099
5100         /*
5101          * Same reg size category.
5102          * A quick note on why we don't require widening here.
5103          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5104          *
5105          * Since the source value comes from a function argument, the JIT will already have
5106          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5107          */
5108         if (param_size <= 4 && return_size <= 4) {
5109                 if (cfg->verbose_level > 3)
5110                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5111                 return TRUE;
5112         }
5113
5114         return FALSE;
5115 }
5116
5117 static MonoInst*
5118 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5119 {
5120         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5121         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5122
5123         if (mini_is_gsharedvt_variable_type (fsig->ret))
5124                 return NULL;
5125
5126         //Valuetypes that are semantically equivalent or numbers than can be widened to
5127         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5128                 return args [0];
5129
5130         //Arrays of valuetypes that are semantically equivalent
5131         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5132                 return args [0];
5133
5134         return NULL;
5135 }
5136
5137 static MonoInst*
5138 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5139 {
5140 #ifdef MONO_ARCH_SIMD_INTRINSICS
5141         MonoInst *ins = NULL;
5142
5143         if (cfg->opt & MONO_OPT_SIMD) {
5144                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5145                 if (ins)
5146                         return ins;
5147         }
5148 #endif
5149
5150         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5151 }
5152
5153 static MonoInst*
5154 emit_memory_barrier (MonoCompile *cfg, int kind)
5155 {
5156         MonoInst *ins = NULL;
5157         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5158         MONO_ADD_INS (cfg->cbb, ins);
5159         ins->backend.memory_barrier_kind = kind;
5160
5161         return ins;
5162 }
5163
5164 static MonoInst*
5165 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5166 {
5167         MonoInst *ins = NULL;
5168         int opcode = 0;
5169
5170         /* The LLVM backend supports these intrinsics */
5171         if (cmethod->klass == mono_defaults.math_class) {
5172                 if (strcmp (cmethod->name, "Sin") == 0) {
5173                         opcode = OP_SIN;
5174                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5175                         opcode = OP_COS;
5176                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5177                         opcode = OP_SQRT;
5178                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5179                         opcode = OP_ABS;
5180                 }
5181
5182                 if (opcode && fsig->param_count == 1) {
5183                         MONO_INST_NEW (cfg, ins, opcode);
5184                         ins->type = STACK_R8;
5185                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5186                         ins->sreg1 = args [0]->dreg;
5187                         MONO_ADD_INS (cfg->cbb, ins);
5188                 }
5189
5190                 opcode = 0;
5191                 if (cfg->opt & MONO_OPT_CMOV) {
5192                         if (strcmp (cmethod->name, "Min") == 0) {
5193                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5194                                         opcode = OP_IMIN;
5195                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5196                                         opcode = OP_IMIN_UN;
5197                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5198                                         opcode = OP_LMIN;
5199                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5200                                         opcode = OP_LMIN_UN;
5201                         } else if (strcmp (cmethod->name, "Max") == 0) {
5202                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5203                                         opcode = OP_IMAX;
5204                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5205                                         opcode = OP_IMAX_UN;
5206                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5207                                         opcode = OP_LMAX;
5208                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5209                                         opcode = OP_LMAX_UN;
5210                         }
5211                 }
5212
5213                 if (opcode && fsig->param_count == 2) {
5214                         MONO_INST_NEW (cfg, ins, opcode);
5215                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5216                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5217                         ins->sreg1 = args [0]->dreg;
5218                         ins->sreg2 = args [1]->dreg;
5219                         MONO_ADD_INS (cfg->cbb, ins);
5220                 }
5221         }
5222
5223         return ins;
5224 }
5225
5226 static MonoInst*
5227 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5228 {
5229         if (cmethod->klass == mono_defaults.array_class) {
5230                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5231                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5232                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5233                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5234                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5235                         return emit_array_unsafe_mov (cfg, fsig, args);
5236         }
5237
5238         return NULL;
5239 }
5240
5241 static MonoInst*
5242 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5243 {
5244         MonoInst *ins = NULL;
5245
5246          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5247
5248         if (cmethod->klass == mono_defaults.string_class) {
5249                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5250                         int dreg = alloc_ireg (cfg);
5251                         int index_reg = alloc_preg (cfg);
5252                         int add_reg = alloc_preg (cfg);
5253
5254 #if SIZEOF_REGISTER == 8
5255                         if (COMPILE_LLVM (cfg)) {
5256                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5257                         } else {
5258                                 /* The array reg is 64 bits but the index reg is only 32 */
5259                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5260                         }
5261 #else
5262                         index_reg = args [1]->dreg;
5263 #endif  
5264                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5265
5266 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5267                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5268                         add_reg = ins->dreg;
5269                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5270                                                                    add_reg, 0);
5271 #else
5272                         int mult_reg = alloc_preg (cfg);
5273                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5274                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5275                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5276                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5277 #endif
5278                         type_from_op (cfg, ins, NULL, NULL);
5279                         return ins;
5280                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5281                         int dreg = alloc_ireg (cfg);
5282                         /* Decompose later to allow more optimizations */
5283                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5284                         ins->type = STACK_I4;
5285                         ins->flags |= MONO_INST_FAULT;
5286                         cfg->cbb->has_array_access = TRUE;
5287                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5288
5289                         return ins;
5290                 } else 
5291                         return NULL;
5292         } else if (cmethod->klass == mono_defaults.object_class) {
5293                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5294                         int dreg = alloc_ireg_ref (cfg);
5295                         int vt_reg = alloc_preg (cfg);
5296                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5297                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5298                         type_from_op (cfg, ins, NULL, NULL);
5299
5300                         return ins;
5301                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5302                         int dreg = alloc_ireg (cfg);
5303                         int t1 = alloc_ireg (cfg);
5304         
5305                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5306                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5307                         ins->type = STACK_I4;
5308
5309                         return ins;
5310                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5311                         MONO_INST_NEW (cfg, ins, OP_NOP);
5312                         MONO_ADD_INS (cfg->cbb, ins);
5313                         return ins;
5314                 } else
5315                         return NULL;
5316         } else if (cmethod->klass == mono_defaults.array_class) {
5317                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5318                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5319                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5320                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5321
5322 #ifndef MONO_BIG_ARRAYS
5323                 /*
5324                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5325                  * Array methods.
5326                  */
5327                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5328                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5329                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5330                         int dreg = alloc_ireg (cfg);
5331                         int bounds_reg = alloc_ireg_mp (cfg);
5332                         MonoBasicBlock *end_bb, *szarray_bb;
5333                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5334
5335                         NEW_BBLOCK (cfg, end_bb);
5336                         NEW_BBLOCK (cfg, szarray_bb);
5337
5338                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5339                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5340                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5341                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5342                         /* Non-szarray case */
5343                         if (get_length)
5344                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5345                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5346                         else
5347                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5348                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5349                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5350                         MONO_START_BB (cfg, szarray_bb);
5351                         /* Szarray case */
5352                         if (get_length)
5353                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5354                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5355                         else
5356                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5357                         MONO_START_BB (cfg, end_bb);
5358
5359                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5360                         ins->type = STACK_I4;
5361                         
5362                         return ins;
5363                 }
5364 #endif
5365
5366                 if (cmethod->name [0] != 'g')
5367                         return NULL;
5368
5369                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5370                         int dreg = alloc_ireg (cfg);
5371                         int vtable_reg = alloc_preg (cfg);
5372                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5373                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5374                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5375                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5376                         type_from_op (cfg, ins, NULL, NULL);
5377
5378                         return ins;
5379                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5380                         int dreg = alloc_ireg (cfg);
5381
5382                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5383                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5384                         type_from_op (cfg, ins, NULL, NULL);
5385
5386                         return ins;
5387                 } else
5388                         return NULL;
5389         } else if (cmethod->klass == runtime_helpers_class) {
5390                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5391                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5392                         return ins;
5393                 } else
5394                         return NULL;
5395         } else if (cmethod->klass == mono_defaults.monitor_class) {
5396                 gboolean is_enter = FALSE;
5397                 gboolean is_v4 = FALSE;
5398
5399                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 2 && fsig->params [1]->byref) {
5400                         is_enter = TRUE;
5401                         is_v4 = TRUE;
5402                 }
5403                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 1)
5404                         is_enter = TRUE;
5405
5406                 if (is_enter) {
5407                         /*
5408                          * To make async stack traces work, icalls which can block should have a wrapper.
5409                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
5410                          */
5411                         MonoBasicBlock *end_bb;
5412
5413                         NEW_BBLOCK (cfg, end_bb);
5414
5415                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
5416                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
5417                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
5418                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_internal : (gpointer)mono_monitor_enter_internal, args);
5419                         MONO_START_BB (cfg, end_bb);
5420                         return ins;
5421                 }
5422         } else if (cmethod->klass == mono_defaults.thread_class) {
5423                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5424                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5425                         MONO_ADD_INS (cfg->cbb, ins);
5426                         return ins;
5427                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5428                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5429                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5430                         guint32 opcode = 0;
5431                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5432
5433                         if (fsig->params [0]->type == MONO_TYPE_I1)
5434                                 opcode = OP_LOADI1_MEMBASE;
5435                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5436                                 opcode = OP_LOADU1_MEMBASE;
5437                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5438                                 opcode = OP_LOADI2_MEMBASE;
5439                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5440                                 opcode = OP_LOADU2_MEMBASE;
5441                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5442                                 opcode = OP_LOADI4_MEMBASE;
5443                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5444                                 opcode = OP_LOADU4_MEMBASE;
5445                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5446                                 opcode = OP_LOADI8_MEMBASE;
5447                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5448                                 opcode = OP_LOADR4_MEMBASE;
5449                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5450                                 opcode = OP_LOADR8_MEMBASE;
5451                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5452                                 opcode = OP_LOAD_MEMBASE;
5453
5454                         if (opcode) {
5455                                 MONO_INST_NEW (cfg, ins, opcode);
5456                                 ins->inst_basereg = args [0]->dreg;
5457                                 ins->inst_offset = 0;
5458                                 MONO_ADD_INS (cfg->cbb, ins);
5459
5460                                 switch (fsig->params [0]->type) {
5461                                 case MONO_TYPE_I1:
5462                                 case MONO_TYPE_U1:
5463                                 case MONO_TYPE_I2:
5464                                 case MONO_TYPE_U2:
5465                                 case MONO_TYPE_I4:
5466                                 case MONO_TYPE_U4:
5467                                         ins->dreg = mono_alloc_ireg (cfg);
5468                                         ins->type = STACK_I4;
5469                                         break;
5470                                 case MONO_TYPE_I8:
5471                                 case MONO_TYPE_U8:
5472                                         ins->dreg = mono_alloc_lreg (cfg);
5473                                         ins->type = STACK_I8;
5474                                         break;
5475                                 case MONO_TYPE_I:
5476                                 case MONO_TYPE_U:
5477                                         ins->dreg = mono_alloc_ireg (cfg);
5478 #if SIZEOF_REGISTER == 8
5479                                         ins->type = STACK_I8;
5480 #else
5481                                         ins->type = STACK_I4;
5482 #endif
5483                                         break;
5484                                 case MONO_TYPE_R4:
5485                                 case MONO_TYPE_R8:
5486                                         ins->dreg = mono_alloc_freg (cfg);
5487                                         ins->type = STACK_R8;
5488                                         break;
5489                                 default:
5490                                         g_assert (mini_type_is_reference (fsig->params [0]));
5491                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5492                                         ins->type = STACK_OBJ;
5493                                         break;
5494                                 }
5495
5496                                 if (opcode == OP_LOADI8_MEMBASE)
5497                                         ins = mono_decompose_opcode (cfg, ins);
5498
5499                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5500
5501                                 return ins;
5502                         }
5503                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5504                         guint32 opcode = 0;
5505                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5506
5507                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5508                                 opcode = OP_STOREI1_MEMBASE_REG;
5509                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5510                                 opcode = OP_STOREI2_MEMBASE_REG;
5511                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5512                                 opcode = OP_STOREI4_MEMBASE_REG;
5513                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5514                                 opcode = OP_STOREI8_MEMBASE_REG;
5515                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5516                                 opcode = OP_STORER4_MEMBASE_REG;
5517                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5518                                 opcode = OP_STORER8_MEMBASE_REG;
5519                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5520                                 opcode = OP_STORE_MEMBASE_REG;
5521
5522                         if (opcode) {
5523                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5524
5525                                 MONO_INST_NEW (cfg, ins, opcode);
5526                                 ins->sreg1 = args [1]->dreg;
5527                                 ins->inst_destbasereg = args [0]->dreg;
5528                                 ins->inst_offset = 0;
5529                                 MONO_ADD_INS (cfg->cbb, ins);
5530
5531                                 if (opcode == OP_STOREI8_MEMBASE_REG)
5532                                         ins = mono_decompose_opcode (cfg, ins);
5533
5534                                 return ins;
5535                         }
5536                 }
5537         } else if (cmethod->klass->image == mono_defaults.corlib &&
5538                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5539                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5540                 ins = NULL;
5541
5542 #if SIZEOF_REGISTER == 8
5543                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5544                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
5545                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
5546                                 ins->dreg = mono_alloc_preg (cfg);
5547                                 ins->sreg1 = args [0]->dreg;
5548                                 ins->type = STACK_I8;
5549                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
5550                                 MONO_ADD_INS (cfg->cbb, ins);
5551                         } else {
5552                                 MonoInst *load_ins;
5553
5554                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5555
5556                                 /* 64 bit reads are already atomic */
5557                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
5558                                 load_ins->dreg = mono_alloc_preg (cfg);
5559                                 load_ins->inst_basereg = args [0]->dreg;
5560                                 load_ins->inst_offset = 0;
5561                                 load_ins->type = STACK_I8;
5562                                 MONO_ADD_INS (cfg->cbb, load_ins);
5563
5564                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5565
5566                                 ins = load_ins;
5567                         }
5568                 }
5569 #endif
5570
5571                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
5572                         MonoInst *ins_iconst;
5573                         guint32 opcode = 0;
5574
5575                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5576                                 opcode = OP_ATOMIC_ADD_I4;
5577                                 cfg->has_atomic_add_i4 = TRUE;
5578                         }
5579 #if SIZEOF_REGISTER == 8
5580                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5581                                 opcode = OP_ATOMIC_ADD_I8;
5582 #endif
5583                         if (opcode) {
5584                                 if (!mono_arch_opcode_supported (opcode))
5585                                         return NULL;
5586                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5587                                 ins_iconst->inst_c0 = 1;
5588                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5589                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5590
5591                                 MONO_INST_NEW (cfg, ins, opcode);
5592                                 ins->dreg = mono_alloc_ireg (cfg);
5593                                 ins->inst_basereg = args [0]->dreg;
5594                                 ins->inst_offset = 0;
5595                                 ins->sreg2 = ins_iconst->dreg;
5596                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5597                                 MONO_ADD_INS (cfg->cbb, ins);
5598                         }
5599                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
5600                         MonoInst *ins_iconst;
5601                         guint32 opcode = 0;
5602
5603                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5604                                 opcode = OP_ATOMIC_ADD_I4;
5605                                 cfg->has_atomic_add_i4 = TRUE;
5606                         }
5607 #if SIZEOF_REGISTER == 8
5608                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5609                                 opcode = OP_ATOMIC_ADD_I8;
5610 #endif
5611                         if (opcode) {
5612                                 if (!mono_arch_opcode_supported (opcode))
5613                                         return NULL;
5614                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5615                                 ins_iconst->inst_c0 = -1;
5616                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5617                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5618
5619                                 MONO_INST_NEW (cfg, ins, opcode);
5620                                 ins->dreg = mono_alloc_ireg (cfg);
5621                                 ins->inst_basereg = args [0]->dreg;
5622                                 ins->inst_offset = 0;
5623                                 ins->sreg2 = ins_iconst->dreg;
5624                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5625                                 MONO_ADD_INS (cfg->cbb, ins);
5626                         }
5627                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
5628                         guint32 opcode = 0;
5629
5630                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5631                                 opcode = OP_ATOMIC_ADD_I4;
5632                                 cfg->has_atomic_add_i4 = TRUE;
5633                         }
5634 #if SIZEOF_REGISTER == 8
5635                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5636                                 opcode = OP_ATOMIC_ADD_I8;
5637 #endif
5638                         if (opcode) {
5639                                 if (!mono_arch_opcode_supported (opcode))
5640                                         return NULL;
5641                                 MONO_INST_NEW (cfg, ins, opcode);
5642                                 ins->dreg = mono_alloc_ireg (cfg);
5643                                 ins->inst_basereg = args [0]->dreg;
5644                                 ins->inst_offset = 0;
5645                                 ins->sreg2 = args [1]->dreg;
5646                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5647                                 MONO_ADD_INS (cfg->cbb, ins);
5648                         }
5649                 }
5650                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
5651                         MonoInst *f2i = NULL, *i2f;
5652                         guint32 opcode, f2i_opcode, i2f_opcode;
5653                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5654                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
5655
5656                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
5657                             fsig->params [0]->type == MONO_TYPE_R4) {
5658                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5659                                 f2i_opcode = OP_MOVE_F_TO_I4;
5660                                 i2f_opcode = OP_MOVE_I4_TO_F;
5661                                 cfg->has_atomic_exchange_i4 = TRUE;
5662                         }
5663 #if SIZEOF_REGISTER == 8
5664                         else if (is_ref ||
5665                                  fsig->params [0]->type == MONO_TYPE_I8 ||
5666                                  fsig->params [0]->type == MONO_TYPE_R8 ||
5667                                  fsig->params [0]->type == MONO_TYPE_I) {
5668                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5669                                 f2i_opcode = OP_MOVE_F_TO_I8;
5670                                 i2f_opcode = OP_MOVE_I8_TO_F;
5671                         }
5672 #else
5673                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
5674                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5675                                 cfg->has_atomic_exchange_i4 = TRUE;
5676                         }
5677 #endif
5678                         else
5679                                 return NULL;
5680
5681                         if (!mono_arch_opcode_supported (opcode))
5682                                 return NULL;
5683
5684                         if (is_float) {
5685                                 /* TODO: Decompose these opcodes instead of bailing here. */
5686                                 if (COMPILE_SOFT_FLOAT (cfg))
5687                                         return NULL;
5688
5689                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
5690                                 f2i->dreg = mono_alloc_ireg (cfg);
5691                                 f2i->sreg1 = args [1]->dreg;
5692                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5693                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5694                                 MONO_ADD_INS (cfg->cbb, f2i);
5695                         }
5696
5697                         MONO_INST_NEW (cfg, ins, opcode);
5698                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5699                         ins->inst_basereg = args [0]->dreg;
5700                         ins->inst_offset = 0;
5701                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
5702                         MONO_ADD_INS (cfg->cbb, ins);
5703
5704                         switch (fsig->params [0]->type) {
5705                         case MONO_TYPE_I4:
5706                                 ins->type = STACK_I4;
5707                                 break;
5708                         case MONO_TYPE_I8:
5709                                 ins->type = STACK_I8;
5710                                 break;
5711                         case MONO_TYPE_I:
5712 #if SIZEOF_REGISTER == 8
5713                                 ins->type = STACK_I8;
5714 #else
5715                                 ins->type = STACK_I4;
5716 #endif
5717                                 break;
5718                         case MONO_TYPE_R4:
5719                         case MONO_TYPE_R8:
5720                                 ins->type = STACK_R8;
5721                                 break;
5722                         default:
5723                                 g_assert (mini_type_is_reference (fsig->params [0]));
5724                                 ins->type = STACK_OBJ;
5725                                 break;
5726                         }
5727
5728                         if (is_float) {
5729                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5730                                 i2f->dreg = mono_alloc_freg (cfg);
5731                                 i2f->sreg1 = ins->dreg;
5732                                 i2f->type = STACK_R8;
5733                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5734                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5735                                 MONO_ADD_INS (cfg->cbb, i2f);
5736
5737                                 ins = i2f;
5738                         }
5739
5740                         if (cfg->gen_write_barriers && is_ref)
5741                                 emit_write_barrier (cfg, args [0], args [1]);
5742                 }
5743                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
5744                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
5745                         guint32 opcode, f2i_opcode, i2f_opcode;
5746                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
5747                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
5748
5749                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
5750                             fsig->params [1]->type == MONO_TYPE_R4) {
5751                                 opcode = OP_ATOMIC_CAS_I4;
5752                                 f2i_opcode = OP_MOVE_F_TO_I4;
5753                                 i2f_opcode = OP_MOVE_I4_TO_F;
5754                                 cfg->has_atomic_cas_i4 = TRUE;
5755                         }
5756 #if SIZEOF_REGISTER == 8
5757                         else if (is_ref ||
5758                                  fsig->params [1]->type == MONO_TYPE_I8 ||
5759                                  fsig->params [1]->type == MONO_TYPE_R8 ||
5760                                  fsig->params [1]->type == MONO_TYPE_I) {
5761                                 opcode = OP_ATOMIC_CAS_I8;
5762                                 f2i_opcode = OP_MOVE_F_TO_I8;
5763                                 i2f_opcode = OP_MOVE_I8_TO_F;
5764                         }
5765 #else
5766                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
5767                                 opcode = OP_ATOMIC_CAS_I4;
5768                                 cfg->has_atomic_cas_i4 = TRUE;
5769                         }
5770 #endif
5771                         else
5772                                 return NULL;
5773
5774                         if (!mono_arch_opcode_supported (opcode))
5775                                 return NULL;
5776
5777                         if (is_float) {
5778                                 /* TODO: Decompose these opcodes instead of bailing here. */
5779                                 if (COMPILE_SOFT_FLOAT (cfg))
5780                                         return NULL;
5781
5782                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
5783                                 f2i_new->dreg = mono_alloc_ireg (cfg);
5784                                 f2i_new->sreg1 = args [1]->dreg;
5785                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5786                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5787                                 MONO_ADD_INS (cfg->cbb, f2i_new);
5788
5789                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
5790                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
5791                                 f2i_cmp->sreg1 = args [2]->dreg;
5792                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5793                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5794                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
5795                         }
5796
5797                         MONO_INST_NEW (cfg, ins, opcode);
5798                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5799                         ins->sreg1 = args [0]->dreg;
5800                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
5801                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
5802                         MONO_ADD_INS (cfg->cbb, ins);
5803
5804                         switch (fsig->params [1]->type) {
5805                         case MONO_TYPE_I4:
5806                                 ins->type = STACK_I4;
5807                                 break;
5808                         case MONO_TYPE_I8:
5809                                 ins->type = STACK_I8;
5810                                 break;
5811                         case MONO_TYPE_I:
5812 #if SIZEOF_REGISTER == 8
5813                                 ins->type = STACK_I8;
5814 #else
5815                                 ins->type = STACK_I4;
5816 #endif
5817                                 break;
5818                         case MONO_TYPE_R4:
5819                                 ins->type = cfg->r4_stack_type;
5820                                 break;
5821                         case MONO_TYPE_R8:
5822                                 ins->type = STACK_R8;
5823                                 break;
5824                         default:
5825                                 g_assert (mini_type_is_reference (fsig->params [1]));
5826                                 ins->type = STACK_OBJ;
5827                                 break;
5828                         }
5829
5830                         if (is_float) {
5831                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5832                                 i2f->dreg = mono_alloc_freg (cfg);
5833                                 i2f->sreg1 = ins->dreg;
5834                                 i2f->type = STACK_R8;
5835                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5836                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5837                                 MONO_ADD_INS (cfg->cbb, i2f);
5838
5839                                 ins = i2f;
5840                         }
5841
5842                         if (cfg->gen_write_barriers && is_ref)
5843                                 emit_write_barrier (cfg, args [0], args [1]);
5844                 }
5845                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
5846                          fsig->params [1]->type == MONO_TYPE_I4) {
5847                         MonoInst *cmp, *ceq;
5848
5849                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5850                                 return NULL;
5851
5852                         /* int32 r = CAS (location, value, comparand); */
5853                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5854                         ins->dreg = alloc_ireg (cfg);
5855                         ins->sreg1 = args [0]->dreg;
5856                         ins->sreg2 = args [1]->dreg;
5857                         ins->sreg3 = args [2]->dreg;
5858                         ins->type = STACK_I4;
5859                         MONO_ADD_INS (cfg->cbb, ins);
5860
5861                         /* bool result = r == comparand; */
5862                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
5863                         cmp->sreg1 = ins->dreg;
5864                         cmp->sreg2 = args [2]->dreg;
5865                         cmp->type = STACK_I4;
5866                         MONO_ADD_INS (cfg->cbb, cmp);
5867
5868                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
5869                         ceq->dreg = alloc_ireg (cfg);
5870                         ceq->type = STACK_I4;
5871                         MONO_ADD_INS (cfg->cbb, ceq);
5872
5873                         /* *success = result; */
5874                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
5875
5876                         cfg->has_atomic_cas_i4 = TRUE;
5877                 }
5878                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
5879                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5880
5881                 if (ins)
5882                         return ins;
5883         } else if (cmethod->klass->image == mono_defaults.corlib &&
5884                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5885                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
5886                 ins = NULL;
5887
5888                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
5889                         guint32 opcode = 0;
5890                         MonoType *t = fsig->params [0];
5891                         gboolean is_ref;
5892                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
5893
5894                         g_assert (t->byref);
5895                         /* t is a byref type, so the reference check is more complicated */
5896                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5897                         if (t->type == MONO_TYPE_I1)
5898                                 opcode = OP_ATOMIC_LOAD_I1;
5899                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5900                                 opcode = OP_ATOMIC_LOAD_U1;
5901                         else if (t->type == MONO_TYPE_I2)
5902                                 opcode = OP_ATOMIC_LOAD_I2;
5903                         else if (t->type == MONO_TYPE_U2)
5904                                 opcode = OP_ATOMIC_LOAD_U2;
5905                         else if (t->type == MONO_TYPE_I4)
5906                                 opcode = OP_ATOMIC_LOAD_I4;
5907                         else if (t->type == MONO_TYPE_U4)
5908                                 opcode = OP_ATOMIC_LOAD_U4;
5909                         else if (t->type == MONO_TYPE_R4)
5910                                 opcode = OP_ATOMIC_LOAD_R4;
5911                         else if (t->type == MONO_TYPE_R8)
5912                                 opcode = OP_ATOMIC_LOAD_R8;
5913 #if SIZEOF_REGISTER == 8
5914                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
5915                                 opcode = OP_ATOMIC_LOAD_I8;
5916                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
5917                                 opcode = OP_ATOMIC_LOAD_U8;
5918 #else
5919                         else if (t->type == MONO_TYPE_I)
5920                                 opcode = OP_ATOMIC_LOAD_I4;
5921                         else if (is_ref || t->type == MONO_TYPE_U)
5922                                 opcode = OP_ATOMIC_LOAD_U4;
5923 #endif
5924
5925                         if (opcode) {
5926                                 if (!mono_arch_opcode_supported (opcode))
5927                                         return NULL;
5928
5929                                 MONO_INST_NEW (cfg, ins, opcode);
5930                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
5931                                 ins->sreg1 = args [0]->dreg;
5932                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
5933                                 MONO_ADD_INS (cfg->cbb, ins);
5934
5935                                 switch (t->type) {
5936                                 case MONO_TYPE_BOOLEAN:
5937                                 case MONO_TYPE_I1:
5938                                 case MONO_TYPE_U1:
5939                                 case MONO_TYPE_I2:
5940                                 case MONO_TYPE_U2:
5941                                 case MONO_TYPE_I4:
5942                                 case MONO_TYPE_U4:
5943                                         ins->type = STACK_I4;
5944                                         break;
5945                                 case MONO_TYPE_I8:
5946                                 case MONO_TYPE_U8:
5947                                         ins->type = STACK_I8;
5948                                         break;
5949                                 case MONO_TYPE_I:
5950                                 case MONO_TYPE_U:
5951 #if SIZEOF_REGISTER == 8
5952                                         ins->type = STACK_I8;
5953 #else
5954                                         ins->type = STACK_I4;
5955 #endif
5956                                         break;
5957                                 case MONO_TYPE_R4:
5958                                         ins->type = cfg->r4_stack_type;
5959                                         break;
5960                                 case MONO_TYPE_R8:
5961                                         ins->type = STACK_R8;
5962                                         break;
5963                                 default:
5964                                         g_assert (is_ref);
5965                                         ins->type = STACK_OBJ;
5966                                         break;
5967                                 }
5968                         }
5969                 }
5970
5971                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
5972                         guint32 opcode = 0;
5973                         MonoType *t = fsig->params [0];
5974                         gboolean is_ref;
5975
5976                         g_assert (t->byref);
5977                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5978                         if (t->type == MONO_TYPE_I1)
5979                                 opcode = OP_ATOMIC_STORE_I1;
5980                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5981                                 opcode = OP_ATOMIC_STORE_U1;
5982                         else if (t->type == MONO_TYPE_I2)
5983                                 opcode = OP_ATOMIC_STORE_I2;
5984                         else if (t->type == MONO_TYPE_U2)
5985                                 opcode = OP_ATOMIC_STORE_U2;
5986                         else if (t->type == MONO_TYPE_I4)
5987                                 opcode = OP_ATOMIC_STORE_I4;
5988                         else if (t->type == MONO_TYPE_U4)
5989                                 opcode = OP_ATOMIC_STORE_U4;
5990                         else if (t->type == MONO_TYPE_R4)
5991                                 opcode = OP_ATOMIC_STORE_R4;
5992                         else if (t->type == MONO_TYPE_R8)
5993                                 opcode = OP_ATOMIC_STORE_R8;
5994 #if SIZEOF_REGISTER == 8
5995                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
5996                                 opcode = OP_ATOMIC_STORE_I8;
5997                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
5998                                 opcode = OP_ATOMIC_STORE_U8;
5999 #else
6000                         else if (t->type == MONO_TYPE_I)
6001                                 opcode = OP_ATOMIC_STORE_I4;
6002                         else if (is_ref || t->type == MONO_TYPE_U)
6003                                 opcode = OP_ATOMIC_STORE_U4;
6004 #endif
6005
6006                         if (opcode) {
6007                                 if (!mono_arch_opcode_supported (opcode))
6008                                         return NULL;
6009
6010                                 MONO_INST_NEW (cfg, ins, opcode);
6011                                 ins->dreg = args [0]->dreg;
6012                                 ins->sreg1 = args [1]->dreg;
6013                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6014                                 MONO_ADD_INS (cfg->cbb, ins);
6015
6016                                 if (cfg->gen_write_barriers && is_ref)
6017                                         emit_write_barrier (cfg, args [0], args [1]);
6018                         }
6019                 }
6020
6021                 if (ins)
6022                         return ins;
6023         } else if (cmethod->klass->image == mono_defaults.corlib &&
6024                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6025                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6026                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6027                         if (should_insert_brekpoint (cfg->method)) {
6028                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6029                         } else {
6030                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6031                                 MONO_ADD_INS (cfg->cbb, ins);
6032                         }
6033                         return ins;
6034                 }
6035         } else if (cmethod->klass->image == mono_defaults.corlib &&
6036                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6037                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6038                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6039 #ifdef TARGET_WIN32
6040                         EMIT_NEW_ICONST (cfg, ins, 1);
6041 #else
6042                         EMIT_NEW_ICONST (cfg, ins, 0);
6043 #endif
6044                 }
6045         } else if (cmethod->klass->image == mono_defaults.corlib &&
6046                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6047                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6048                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6049                         /* No stack walks are currently available, so implement this as an intrinsic */
6050                         MonoInst *assembly_ins;
6051
6052                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6053                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6054                         return ins;
6055                 }
6056         } else if (cmethod->klass->image == mono_defaults.corlib &&
6057                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6058                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6059                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6060                         /* No stack walks are currently available, so implement this as an intrinsic */
6061                         MonoInst *method_ins;
6062                         MonoMethod *declaring = cfg->method;
6063
6064                         /* This returns the declaring generic method */
6065                         if (declaring->is_inflated)
6066                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6067                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6068                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6069                         cfg->no_inline = TRUE;
6070                         if (cfg->method != cfg->current_method)
6071                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6072                         return ins;
6073                 }
6074         } else if (cmethod->klass == mono_defaults.math_class) {
6075                 /* 
6076                  * There is general branchless code for Min/Max, but it does not work for 
6077                  * all inputs:
6078                  * http://everything2.com/?node_id=1051618
6079                  */
6080         } else if (cmethod->klass == mono_defaults.systemtype_class && !strcmp (cmethod->name, "op_Equality")) {
6081                 EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg);
6082                 MONO_INST_NEW (cfg, ins, OP_PCEQ);
6083                 ins->dreg = alloc_preg (cfg);
6084                 ins->type = STACK_I4;
6085                 MONO_ADD_INS (cfg->cbb, ins);
6086                 return ins;
6087         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6088                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6089                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6090                                 !strcmp (cmethod->klass->name, "Selector")) ||
6091                            ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
6092                                  !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
6093                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6094                                 !strcmp (cmethod->klass->name, "Selector"))
6095                            ) {
6096                 if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
6097                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6098                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6099                     cfg->compile_aot) {
6100                         MonoInst *pi;
6101                         MonoJumpInfoToken *ji;
6102                         char *s;
6103
6104                         if (args [0]->opcode == OP_GOT_ENTRY) {
6105                                 pi = (MonoInst *)args [0]->inst_p1;
6106                                 g_assert (pi->opcode == OP_PATCH_INFO);
6107                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6108                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6109                         } else {
6110                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6111                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6112                         }
6113
6114                         NULLIFY_INS (args [0]);
6115
6116                         s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
6117                         return_val_if_nok (&cfg->error, NULL);
6118
6119                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6120                         ins->dreg = mono_alloc_ireg (cfg);
6121                         // FIXME: Leaks
6122                         ins->inst_p0 = s;
6123                         MONO_ADD_INS (cfg->cbb, ins);
6124                         return ins;
6125                 }
6126         }
6127
6128 #ifdef MONO_ARCH_SIMD_INTRINSICS
6129         if (cfg->opt & MONO_OPT_SIMD) {
6130                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6131                 if (ins)
6132                         return ins;
6133         }
6134 #endif
6135
6136         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6137         if (ins)
6138                 return ins;
6139
6140         if (COMPILE_LLVM (cfg)) {
6141                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6142                 if (ins)
6143                         return ins;
6144         }
6145
6146         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6147 }
6148
6149 /*
6150  * This entry point could be used later for arbitrary method
6151  * redirection.
6152  */
6153 inline static MonoInst*
6154 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6155                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6156 {
6157         if (method->klass == mono_defaults.string_class) {
6158                 /* managed string allocation support */
6159                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6160                         MonoInst *iargs [2];
6161                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6162                         MonoMethod *managed_alloc = NULL;
6163
6164                         g_assert (vtable); /*Should not fail since it System.String*/
6165 #ifndef MONO_CROSS_COMPILE
6166                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6167 #endif
6168                         if (!managed_alloc)
6169                                 return NULL;
6170                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6171                         iargs [1] = args [0];
6172                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6173                 }
6174         }
6175         return NULL;
6176 }
6177
6178 static void
6179 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6180 {
6181         MonoInst *store, *temp;
6182         int i;
6183
6184         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6185                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6186
6187                 /*
6188                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6189                  * would be different than the MonoInst's used to represent arguments, and
6190                  * the ldelema implementation can't deal with that.
6191                  * Solution: When ldelema is used on an inline argument, create a var for 
6192                  * it, emit ldelema on that var, and emit the saving code below in
6193                  * inline_method () if needed.
6194                  */
6195                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6196                 cfg->args [i] = temp;
6197                 /* This uses cfg->args [i] which is set by the preceeding line */
6198                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6199                 store->cil_code = sp [0]->cil_code;
6200                 sp++;
6201         }
6202 }
6203
6204 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6205 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6206
6207 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6208 static gboolean
6209 check_inline_called_method_name_limit (MonoMethod *called_method)
6210 {
6211         int strncmp_result;
6212         static const char *limit = NULL;
6213         
6214         if (limit == NULL) {
6215                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6216
6217                 if (limit_string != NULL)
6218                         limit = limit_string;
6219                 else
6220                         limit = "";
6221         }
6222
6223         if (limit [0] != '\0') {
6224                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6225
6226                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6227                 g_free (called_method_name);
6228         
6229                 //return (strncmp_result <= 0);
6230                 return (strncmp_result == 0);
6231         } else {
6232                 return TRUE;
6233         }
6234 }
6235 #endif
6236
6237 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6238 static gboolean
6239 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6240 {
6241         int strncmp_result;
6242         static const char *limit = NULL;
6243         
6244         if (limit == NULL) {
6245                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6246                 if (limit_string != NULL) {
6247                         limit = limit_string;
6248                 } else {
6249                         limit = "";
6250                 }
6251         }
6252
6253         if (limit [0] != '\0') {
6254                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6255
6256                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6257                 g_free (caller_method_name);
6258         
6259                 //return (strncmp_result <= 0);
6260                 return (strncmp_result == 0);
6261         } else {
6262                 return TRUE;
6263         }
6264 }
6265 #endif
6266
6267 static void
6268 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6269 {
6270         static double r8_0 = 0.0;
6271         static float r4_0 = 0.0;
6272         MonoInst *ins;
6273         int t;
6274
6275         rtype = mini_get_underlying_type (rtype);
6276         t = rtype->type;
6277
6278         if (rtype->byref) {
6279                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6280         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6281                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6282         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6283                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6284         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6285                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6286                 ins->type = STACK_R4;
6287                 ins->inst_p0 = (void*)&r4_0;
6288                 ins->dreg = dreg;
6289                 MONO_ADD_INS (cfg->cbb, ins);
6290         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6291                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6292                 ins->type = STACK_R8;
6293                 ins->inst_p0 = (void*)&r8_0;
6294                 ins->dreg = dreg;
6295                 MONO_ADD_INS (cfg->cbb, ins);
6296         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6297                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6298                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6299         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6300                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6301         } else {
6302                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6303         }
6304 }
6305
6306 static void
6307 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6308 {
6309         int t;
6310
6311         rtype = mini_get_underlying_type (rtype);
6312         t = rtype->type;
6313
6314         if (rtype->byref) {
6315                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6316         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6317                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6318         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6319                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6320         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6321                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6322         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6323                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6324         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6325                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6326                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6327         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6328                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6329         } else {
6330                 emit_init_rvar (cfg, dreg, rtype);
6331         }
6332 }
6333
6334 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6335 static void
6336 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6337 {
6338         MonoInst *var = cfg->locals [local];
6339         if (COMPILE_SOFT_FLOAT (cfg)) {
6340                 MonoInst *store;
6341                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
6342                 emit_init_rvar (cfg, reg, type);
6343                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6344         } else {
6345                 if (init)
6346                         emit_init_rvar (cfg, var->dreg, type);
6347                 else
6348                         emit_dummy_init_rvar (cfg, var->dreg, type);
6349         }
6350 }
6351
6352 int
6353 mini_inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, guchar *ip, guint real_offset, gboolean inline_always)
6354 {
6355         return inline_method (cfg, cmethod, fsig, sp, ip, real_offset, inline_always);
6356 }
6357
6358 /*
6359  * inline_method:
6360  *
6361  * Return the cost of inlining CMETHOD, or zero if it should not be inlined.
6362  */
6363 static int
6364 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6365                guchar *ip, guint real_offset, gboolean inline_always)
6366 {
6367         MonoError error;
6368         MonoInst *ins, *rvar = NULL;
6369         MonoMethodHeader *cheader;
6370         MonoBasicBlock *ebblock, *sbblock;
6371         int i, costs;
6372         MonoMethod *prev_inlined_method;
6373         MonoInst **prev_locals, **prev_args;
6374         MonoType **prev_arg_types;
6375         guint prev_real_offset;
6376         GHashTable *prev_cbb_hash;
6377         MonoBasicBlock **prev_cil_offset_to_bb;
6378         MonoBasicBlock *prev_cbb;
6379         const unsigned char *prev_ip;
6380         unsigned char *prev_cil_start;
6381         guint32 prev_cil_offset_to_bb_len;
6382         MonoMethod *prev_current_method;
6383         MonoGenericContext *prev_generic_context;
6384         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
6385
6386         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6387
6388 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6389         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6390                 return 0;
6391 #endif
6392 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6393         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6394                 return 0;
6395 #endif
6396
6397         if (!fsig)
6398                 fsig = mono_method_signature (cmethod);
6399
6400         if (cfg->verbose_level > 2)
6401                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6402
6403         if (!cmethod->inline_info) {
6404                 cfg->stat_inlineable_methods++;
6405                 cmethod->inline_info = 1;
6406         }
6407
6408         /* allocate local variables */
6409         cheader = mono_method_get_header_checked (cmethod, &error);
6410         if (!cheader) {
6411                 if (inline_always) {
6412                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
6413                         mono_error_move (&cfg->error, &error);
6414                 } else {
6415                         mono_error_cleanup (&error);
6416                 }
6417                 return 0;
6418         }
6419
6420         /*Must verify before creating locals as it can cause the JIT to assert.*/
6421         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6422                 mono_metadata_free_mh (cheader);
6423                 return 0;
6424         }
6425
6426         /* allocate space to store the return value */
6427         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6428                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6429         }
6430
6431         prev_locals = cfg->locals;
6432         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
6433         for (i = 0; i < cheader->num_locals; ++i)
6434                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6435
6436         /* allocate start and end blocks */
6437         /* This is needed so if the inline is aborted, we can clean up */
6438         NEW_BBLOCK (cfg, sbblock);
6439         sbblock->real_offset = real_offset;
6440
6441         NEW_BBLOCK (cfg, ebblock);
6442         ebblock->block_num = cfg->num_bblocks++;
6443         ebblock->real_offset = real_offset;
6444
6445         prev_args = cfg->args;
6446         prev_arg_types = cfg->arg_types;
6447         prev_inlined_method = cfg->inlined_method;
6448         cfg->inlined_method = cmethod;
6449         cfg->ret_var_set = FALSE;
6450         cfg->inline_depth ++;
6451         prev_real_offset = cfg->real_offset;
6452         prev_cbb_hash = cfg->cbb_hash;
6453         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6454         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6455         prev_cil_start = cfg->cil_start;
6456         prev_ip = cfg->ip;
6457         prev_cbb = cfg->cbb;
6458         prev_current_method = cfg->current_method;
6459         prev_generic_context = cfg->generic_context;
6460         prev_ret_var_set = cfg->ret_var_set;
6461         prev_disable_inline = cfg->disable_inline;
6462
6463         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6464                 virtual_ = TRUE;
6465
6466         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
6467
6468         ret_var_set = cfg->ret_var_set;
6469
6470         cfg->inlined_method = prev_inlined_method;
6471         cfg->real_offset = prev_real_offset;
6472         cfg->cbb_hash = prev_cbb_hash;
6473         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6474         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6475         cfg->cil_start = prev_cil_start;
6476         cfg->ip = prev_ip;
6477         cfg->locals = prev_locals;
6478         cfg->args = prev_args;
6479         cfg->arg_types = prev_arg_types;
6480         cfg->current_method = prev_current_method;
6481         cfg->generic_context = prev_generic_context;
6482         cfg->ret_var_set = prev_ret_var_set;
6483         cfg->disable_inline = prev_disable_inline;
6484         cfg->inline_depth --;
6485
6486         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
6487                 if (cfg->verbose_level > 2)
6488                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6489
6490                 cfg->stat_inlined_methods++;
6491
6492                 /* always add some code to avoid block split failures */
6493                 MONO_INST_NEW (cfg, ins, OP_NOP);
6494                 MONO_ADD_INS (prev_cbb, ins);
6495
6496                 prev_cbb->next_bb = sbblock;
6497                 link_bblock (cfg, prev_cbb, sbblock);
6498
6499                 /* 
6500                  * Get rid of the begin and end bblocks if possible to aid local
6501                  * optimizations.
6502                  */
6503                 if (prev_cbb->out_count == 1)
6504                         mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6505
6506                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6507                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6508
6509                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6510                         MonoBasicBlock *prev = ebblock->in_bb [0];
6511
6512                         if (prev->next_bb == ebblock) {
6513                                 mono_merge_basic_blocks (cfg, prev, ebblock);
6514                                 cfg->cbb = prev;
6515                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6516                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
6517                                         cfg->cbb = prev_cbb;
6518                                 }
6519                         } else {
6520                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
6521                                 cfg->cbb = ebblock;
6522                         }
6523                 } else {
6524                         /* 
6525                          * Its possible that the rvar is set in some prev bblock, but not in others.
6526                          * (#1835).
6527                          */
6528                         if (rvar) {
6529                                 MonoBasicBlock *bb;
6530
6531                                 for (i = 0; i < ebblock->in_count; ++i) {
6532                                         bb = ebblock->in_bb [i];
6533
6534                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6535                                                 cfg->cbb = bb;
6536
6537                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6538                                         }
6539                                 }
6540                         }
6541
6542                         cfg->cbb = ebblock;
6543                 }
6544
6545                 if (rvar) {
6546                         /*
6547                          * If the inlined method contains only a throw, then the ret var is not 
6548                          * set, so set it to a dummy value.
6549                          */
6550                         if (!ret_var_set)
6551                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6552
6553                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6554                         *sp++ = ins;
6555                 }
6556                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6557                 return costs + 1;
6558         } else {
6559                 if (cfg->verbose_level > 2)
6560                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6561                 cfg->exception_type = MONO_EXCEPTION_NONE;
6562
6563                 /* This gets rid of the newly added bblocks */
6564                 cfg->cbb = prev_cbb;
6565         }
6566         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6567         return 0;
6568 }
6569
6570 /*
6571  * Some of these comments may well be out-of-date.
6572  * Design decisions: we do a single pass over the IL code (and we do bblock 
6573  * splitting/merging in the few cases when it's required: a back jump to an IL
6574  * address that was not already seen as bblock starting point).
6575  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6576  * Complex operations are decomposed in simpler ones right away. We need to let the 
6577  * arch-specific code peek and poke inside this process somehow (except when the 
6578  * optimizations can take advantage of the full semantic info of coarse opcodes).
6579  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6580  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6581  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6582  * opcode with value bigger than OP_LAST.
6583  * At this point the IR can be handed over to an interpreter, a dumb code generator
6584  * or to the optimizing code generator that will translate it to SSA form.
6585  *
6586  * Profiling directed optimizations.
6587  * We may compile by default with few or no optimizations and instrument the code
6588  * or the user may indicate what methods to optimize the most either in a config file
6589  * or through repeated runs where the compiler applies offline the optimizations to 
6590  * each method and then decides if it was worth it.
6591  */
6592
6593 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6594 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6595 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6596 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6597 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6598 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6599 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6600 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
6601
6602 /* offset from br.s -> br like opcodes */
6603 #define BIG_BRANCH_OFFSET 13
6604
6605 static gboolean
6606 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6607 {
6608         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6609
6610         return b == NULL || b == bb;
6611 }
6612
6613 static int
6614 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6615 {
6616         unsigned char *ip = start;
6617         unsigned char *target;
6618         int i;
6619         guint cli_addr;
6620         MonoBasicBlock *bblock;
6621         const MonoOpcode *opcode;
6622
6623         while (ip < end) {
6624                 cli_addr = ip - start;
6625                 i = mono_opcode_value ((const guint8 **)&ip, end);
6626                 if (i < 0)
6627                         UNVERIFIED;
6628                 opcode = &mono_opcodes [i];
6629                 switch (opcode->argument) {
6630                 case MonoInlineNone:
6631                         ip++; 
6632                         break;
6633                 case MonoInlineString:
6634                 case MonoInlineType:
6635                 case MonoInlineField:
6636                 case MonoInlineMethod:
6637                 case MonoInlineTok:
6638                 case MonoInlineSig:
6639                 case MonoShortInlineR:
6640                 case MonoInlineI:
6641                         ip += 5;
6642                         break;
6643                 case MonoInlineVar:
6644                         ip += 3;
6645                         break;
6646                 case MonoShortInlineVar:
6647                 case MonoShortInlineI:
6648                         ip += 2;
6649                         break;
6650                 case MonoShortInlineBrTarget:
6651                         target = start + cli_addr + 2 + (signed char)ip [1];
6652                         GET_BBLOCK (cfg, bblock, target);
6653                         ip += 2;
6654                         if (ip < end)
6655                                 GET_BBLOCK (cfg, bblock, ip);
6656                         break;
6657                 case MonoInlineBrTarget:
6658                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6659                         GET_BBLOCK (cfg, bblock, target);
6660                         ip += 5;
6661                         if (ip < end)
6662                                 GET_BBLOCK (cfg, bblock, ip);
6663                         break;
6664                 case MonoInlineSwitch: {
6665                         guint32 n = read32 (ip + 1);
6666                         guint32 j;
6667                         ip += 5;
6668                         cli_addr += 5 + 4 * n;
6669                         target = start + cli_addr;
6670                         GET_BBLOCK (cfg, bblock, target);
6671                         
6672                         for (j = 0; j < n; ++j) {
6673                                 target = start + cli_addr + (gint32)read32 (ip);
6674                                 GET_BBLOCK (cfg, bblock, target);
6675                                 ip += 4;
6676                         }
6677                         break;
6678                 }
6679                 case MonoInlineR:
6680                 case MonoInlineI8:
6681                         ip += 9;
6682                         break;
6683                 default:
6684                         g_assert_not_reached ();
6685                 }
6686
6687                 if (i == CEE_THROW) {
6688                         unsigned char *bb_start = ip - 1;
6689                         
6690                         /* Find the start of the bblock containing the throw */
6691                         bblock = NULL;
6692                         while ((bb_start >= start) && !bblock) {
6693                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6694                                 bb_start --;
6695                         }
6696                         if (bblock)
6697                                 bblock->out_of_line = 1;
6698                 }
6699         }
6700         return 0;
6701 unverified:
6702 exception_exit:
6703         *pos = ip;
6704         return 1;
6705 }
6706
6707 static inline MonoMethod *
6708 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
6709 {
6710         MonoMethod *method;
6711
6712         error_init (error);
6713
6714         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6715                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
6716                 if (context) {
6717                         method = mono_class_inflate_generic_method_checked (method, context, error);
6718                 }
6719         } else {
6720                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
6721         }
6722
6723         return method;
6724 }
6725
6726 static inline MonoMethod *
6727 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6728 {
6729         MonoError error;
6730         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
6731
6732         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
6733                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
6734                 method = NULL;
6735         }
6736
6737         if (!method && !cfg)
6738                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6739
6740         return method;
6741 }
6742
6743 static inline MonoClass*
6744 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6745 {
6746         MonoError error;
6747         MonoClass *klass;
6748
6749         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6750                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
6751                 if (context) {
6752                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
6753                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6754                 }
6755         } else {
6756                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
6757                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6758         }
6759         if (klass)
6760                 mono_class_init (klass);
6761         return klass;
6762 }
6763
6764 static inline MonoMethodSignature*
6765 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
6766 {
6767         MonoMethodSignature *fsig;
6768
6769         error_init (error);
6770         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6771                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6772         } else {
6773                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
6774                 return_val_if_nok (error, NULL);
6775         }
6776         if (context) {
6777                 fsig = mono_inflate_generic_signature(fsig, context, error);
6778         }
6779         return fsig;
6780 }
6781
6782 static MonoMethod*
6783 throw_exception (void)
6784 {
6785         static MonoMethod *method = NULL;
6786
6787         if (!method) {
6788                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6789                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6790         }
6791         g_assert (method);
6792         return method;
6793 }
6794
6795 static void
6796 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6797 {
6798         MonoMethod *thrower = throw_exception ();
6799         MonoInst *args [1];
6800
6801         EMIT_NEW_PCONST (cfg, args [0], ex);
6802         mono_emit_method_call (cfg, thrower, args, NULL);
6803 }
6804
6805 /*
6806  * Return the original method is a wrapper is specified. We can only access 
6807  * the custom attributes from the original method.
6808  */
6809 static MonoMethod*
6810 get_original_method (MonoMethod *method)
6811 {
6812         if (method->wrapper_type == MONO_WRAPPER_NONE)
6813                 return method;
6814
6815         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6816         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6817                 return NULL;
6818
6819         /* in other cases we need to find the original method */
6820         return mono_marshal_method_from_wrapper (method);
6821 }
6822
6823 static void
6824 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
6825 {
6826         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6827         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6828         if (ex)
6829                 emit_throw_exception (cfg, ex);
6830 }
6831
6832 static void
6833 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6834 {
6835         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6836         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6837         if (ex)
6838                 emit_throw_exception (cfg, ex);
6839 }
6840
6841 /*
6842  * Check that the IL instructions at ip are the array initialization
6843  * sequence and return the pointer to the data and the size.
6844  */
6845 static const char*
6846 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6847 {
6848         /*
6849          * newarr[System.Int32]
6850          * dup
6851          * ldtoken field valuetype ...
6852          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6853          */
6854         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6855                 MonoError error;
6856                 guint32 token = read32 (ip + 7);
6857                 guint32 field_token = read32 (ip + 2);
6858                 guint32 field_index = field_token & 0xffffff;
6859                 guint32 rva;
6860                 const char *data_ptr;
6861                 int size = 0;
6862                 MonoMethod *cmethod;
6863                 MonoClass *dummy_class;
6864                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
6865                 int dummy_align;
6866
6867                 if (!field) {
6868                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6869                         return NULL;
6870                 }
6871
6872                 *out_field_token = field_token;
6873
6874                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6875                 if (!cmethod)
6876                         return NULL;
6877                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6878                         return NULL;
6879                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6880                 case MONO_TYPE_BOOLEAN:
6881                 case MONO_TYPE_I1:
6882                 case MONO_TYPE_U1:
6883                         size = 1; break;
6884                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6885 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6886                 case MONO_TYPE_CHAR:
6887                 case MONO_TYPE_I2:
6888                 case MONO_TYPE_U2:
6889                         size = 2; break;
6890                 case MONO_TYPE_I4:
6891                 case MONO_TYPE_U4:
6892                 case MONO_TYPE_R4:
6893                         size = 4; break;
6894                 case MONO_TYPE_R8:
6895                 case MONO_TYPE_I8:
6896                 case MONO_TYPE_U8:
6897                         size = 8; break;
6898 #endif
6899                 default:
6900                         return NULL;
6901                 }
6902                 size *= len;
6903                 if (size > mono_type_size (field->type, &dummy_align))
6904                     return NULL;
6905                 *out_size = size;
6906                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6907                 if (!image_is_dynamic (method->klass->image)) {
6908                         field_index = read32 (ip + 2) & 0xffffff;
6909                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6910                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6911                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6912                         /* for aot code we do the lookup on load */
6913                         if (aot && data_ptr)
6914                                 return (const char *)GUINT_TO_POINTER (rva);
6915                 } else {
6916                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6917                         g_assert (!aot);
6918                         data_ptr = mono_field_get_data (field);
6919                 }
6920                 return data_ptr;
6921         }
6922         return NULL;
6923 }
6924
6925 static void
6926 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6927 {
6928         MonoError error;
6929         char *method_fname = mono_method_full_name (method, TRUE);
6930         char *method_code;
6931         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
6932
6933         if (!header) {
6934                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
6935                 mono_error_cleanup (&error);
6936         } else if (header->code_size == 0)
6937                 method_code = g_strdup ("method body is empty.");
6938         else
6939                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6940         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
6941         g_free (method_fname);
6942         g_free (method_code);
6943         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6944 }
6945
6946 static void
6947 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6948 {
6949         MonoInst *ins;
6950         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6951         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6952                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6953                 /* Optimize reg-reg moves away */
6954                 /* 
6955                  * Can't optimize other opcodes, since sp[0] might point to
6956                  * the last ins of a decomposed opcode.
6957                  */
6958                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6959         } else {
6960                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6961         }
6962 }
6963
6964 /*
6965  * ldloca inhibits many optimizations so try to get rid of it in common
6966  * cases.
6967  */
6968 static inline unsigned char *
6969 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6970 {
6971         int local, token;
6972         MonoClass *klass;
6973         MonoType *type;
6974
6975         if (size == 1) {
6976                 local = ip [1];
6977                 ip += 2;
6978         } else {
6979                 local = read16 (ip + 2);
6980                 ip += 4;
6981         }
6982         
6983         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6984                 /* From the INITOBJ case */
6985                 token = read32 (ip + 2);
6986                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6987                 CHECK_TYPELOAD (klass);
6988                 type = mini_get_underlying_type (&klass->byval_arg);
6989                 emit_init_local (cfg, local, type, TRUE);
6990                 return ip + 6;
6991         }
6992  exception_exit:
6993         return NULL;
6994 }
6995
6996 static MonoInst*
6997 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
6998 {
6999         MonoInst *icall_args [16];
7000         MonoInst *call_target, *ins, *vtable_ins;
7001         int arg_reg, this_reg, vtable_reg;
7002         gboolean is_iface = mono_class_is_interface (cmethod->klass);
7003         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7004         gboolean variant_iface = FALSE;
7005         guint32 slot;
7006         int offset;
7007         gboolean special_array_interface = cmethod->klass->is_array_special_interface;
7008
7009         /*
7010          * In llvm-only mode, vtables contain function descriptors instead of
7011          * method addresses/trampolines.
7012          */
7013         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7014
7015         if (is_iface)
7016                 slot = mono_method_get_imt_slot (cmethod);
7017         else
7018                 slot = mono_method_get_vtable_index (cmethod);
7019
7020         this_reg = sp [0]->dreg;
7021
7022         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7023                 variant_iface = TRUE;
7024
7025         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7026                 /*
7027                  * The simplest case, a normal virtual call.
7028                  */
7029                 int slot_reg = alloc_preg (cfg);
7030                 int addr_reg = alloc_preg (cfg);
7031                 int arg_reg = alloc_preg (cfg);
7032                 MonoBasicBlock *non_null_bb;
7033
7034                 vtable_reg = alloc_preg (cfg);
7035                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7036                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7037
7038                 /* Load the vtable slot, which contains a function descriptor. */
7039                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7040
7041                 NEW_BBLOCK (cfg, non_null_bb);
7042
7043                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7044                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7045                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7046
7047                 /* Slow path */
7048                 // FIXME: Make the wrapper use the preserveall cconv
7049                 // FIXME: Use one icall per slot for small slot numbers ?
7050                 icall_args [0] = vtable_ins;
7051                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7052                 /* Make the icall return the vtable slot value to save some code space */
7053                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7054                 ins->dreg = slot_reg;
7055                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7056
7057                 /* Fastpath */
7058                 MONO_START_BB (cfg, non_null_bb);
7059                 /* Load the address + arg from the vtable slot */
7060                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7061                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7062
7063                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7064         }
7065
7066         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt && !special_array_interface) {
7067                 /*
7068                  * A simple interface call
7069                  *
7070                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7071                  * The imt slot contains a function descriptor for a runtime function + arg.
7072                  */
7073                 int slot_reg = alloc_preg (cfg);
7074                 int addr_reg = alloc_preg (cfg);
7075                 int arg_reg = alloc_preg (cfg);
7076                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7077
7078                 vtable_reg = alloc_preg (cfg);
7079                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7080                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7081
7082                 /*
7083                  * The slot is already initialized when the vtable is created so there is no need
7084                  * to check it here.
7085                  */
7086
7087                 /* Load the imt slot, which contains a function descriptor. */
7088                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7089
7090                 /* Load the address + arg of the imt thunk from the imt slot */
7091                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7092                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7093                 /*
7094                  * IMT thunks in llvm-only mode are C functions which take an info argument
7095                  * plus the imt method and return the ftndesc to call.
7096                  */
7097                 icall_args [0] = thunk_arg_ins;
7098                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7099                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7100                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7101
7102                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7103         }
7104
7105         if ((fsig->generic_param_count || variant_iface || special_array_interface) && !is_gsharedvt) {
7106                 /*
7107                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7108                  * dynamically extended as more instantiations are discovered.
7109                  * This handles generic virtual methods both on classes and interfaces.
7110                  */
7111                 int slot_reg = alloc_preg (cfg);
7112                 int addr_reg = alloc_preg (cfg);
7113                 int arg_reg = alloc_preg (cfg);
7114                 int ftndesc_reg = alloc_preg (cfg);
7115                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7116                 MonoBasicBlock *slowpath_bb, *end_bb;
7117
7118                 NEW_BBLOCK (cfg, slowpath_bb);
7119                 NEW_BBLOCK (cfg, end_bb);
7120
7121                 vtable_reg = alloc_preg (cfg);
7122                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7123                 if (is_iface)
7124                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7125                 else
7126                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7127
7128                 /* Load the slot, which contains a function descriptor. */
7129                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7130
7131                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7132                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7133                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7134                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7135
7136                 /* Fastpath */
7137                 /* Same as with iface calls */
7138                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7139                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7140                 icall_args [0] = thunk_arg_ins;
7141                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7142                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7143                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7144                 ftndesc_ins->dreg = ftndesc_reg;
7145                 /*
7146                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7147                  * they don't know about yet. Fall back to the slowpath in that case.
7148                  */
7149                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7150                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7151
7152                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7153
7154                 /* Slowpath */
7155                 MONO_START_BB (cfg, slowpath_bb);
7156                 icall_args [0] = vtable_ins;
7157                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7158                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7159                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7160                 if (is_iface)
7161                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7162                 else
7163                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7164                 ftndesc_ins->dreg = ftndesc_reg;
7165                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7166
7167                 /* Common case */
7168                 MONO_START_BB (cfg, end_bb);
7169                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7170         }
7171
7172         /*
7173          * Non-optimized cases
7174          */
7175         icall_args [0] = sp [0];
7176         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7177
7178         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7179                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7180
7181         arg_reg = alloc_preg (cfg);
7182         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7183         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7184
7185         g_assert (is_gsharedvt);
7186         if (is_iface)
7187                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7188         else
7189                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7190
7191         /*
7192          * Pass the extra argument even if the callee doesn't receive it, most
7193          * calling conventions allow this.
7194          */
7195         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7196 }
7197
7198 static gboolean
7199 is_exception_class (MonoClass *klass)
7200 {
7201         while (klass) {
7202                 if (klass == mono_defaults.exception_class)
7203                         return TRUE;
7204                 klass = klass->parent;
7205         }
7206         return FALSE;
7207 }
7208
7209 /*
7210  * is_jit_optimizer_disabled:
7211  *
7212  *   Determine whenever M's assembly has a DebuggableAttribute with the
7213  * IsJITOptimizerDisabled flag set.
7214  */
7215 static gboolean
7216 is_jit_optimizer_disabled (MonoMethod *m)
7217 {
7218         MonoError error;
7219         MonoAssembly *ass = m->klass->image->assembly;
7220         MonoCustomAttrInfo* attrs;
7221         MonoClass *klass;
7222         int i;
7223         gboolean val = FALSE;
7224
7225         g_assert (ass);
7226         if (ass->jit_optimizer_disabled_inited)
7227                 return ass->jit_optimizer_disabled;
7228
7229         klass = mono_class_try_get_debuggable_attribute_class ();
7230
7231         if (!klass) {
7232                 /* Linked away */
7233                 ass->jit_optimizer_disabled = FALSE;
7234                 mono_memory_barrier ();
7235                 ass->jit_optimizer_disabled_inited = TRUE;
7236                 return FALSE;
7237         }
7238
7239         attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
7240         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7241         if (attrs) {
7242                 for (i = 0; i < attrs->num_attrs; ++i) {
7243                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7244                         const gchar *p;
7245                         MonoMethodSignature *sig;
7246
7247                         if (!attr->ctor || attr->ctor->klass != klass)
7248                                 continue;
7249                         /* Decode the attribute. See reflection.c */
7250                         p = (const char*)attr->data;
7251                         g_assert (read16 (p) == 0x0001);
7252                         p += 2;
7253
7254                         // FIXME: Support named parameters
7255                         sig = mono_method_signature (attr->ctor);
7256                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7257                                 continue;
7258                         /* Two boolean arguments */
7259                         p ++;
7260                         val = *p;
7261                 }
7262                 mono_custom_attrs_free (attrs);
7263         }
7264
7265         ass->jit_optimizer_disabled = val;
7266         mono_memory_barrier ();
7267         ass->jit_optimizer_disabled_inited = TRUE;
7268
7269         return val;
7270 }
7271
7272 static gboolean
7273 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7274 {
7275         gboolean supported_tail_call;
7276         int i;
7277
7278         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7279
7280         for (i = 0; i < fsig->param_count; ++i) {
7281                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7282                         /* These can point to the current method's stack */
7283                         supported_tail_call = FALSE;
7284         }
7285         if (fsig->hasthis && cmethod->klass->valuetype)
7286                 /* this might point to the current method's stack */
7287                 supported_tail_call = FALSE;
7288         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7289                 supported_tail_call = FALSE;
7290         if (cfg->method->save_lmf)
7291                 supported_tail_call = FALSE;
7292         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7293                 supported_tail_call = FALSE;
7294         if (call_opcode != CEE_CALL)
7295                 supported_tail_call = FALSE;
7296
7297         /* Debugging support */
7298 #if 0
7299         if (supported_tail_call) {
7300                 if (!mono_debug_count ())
7301                         supported_tail_call = FALSE;
7302         }
7303 #endif
7304
7305         return supported_tail_call;
7306 }
7307
7308 /*
7309  * handle_ctor_call:
7310  *
7311  *   Handle calls made to ctors from NEWOBJ opcodes.
7312  */
7313 static void
7314 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7315                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7316 {
7317         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7318
7319         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7320                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7321                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7322                         mono_class_vtable (cfg->domain, cmethod->klass);
7323                         CHECK_TYPELOAD (cmethod->klass);
7324
7325                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7326                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7327                 } else {
7328                         if (context_used) {
7329                                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
7330                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7331                         } else {
7332                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7333
7334                                 CHECK_TYPELOAD (cmethod->klass);
7335                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7336                         }
7337                 }
7338         }
7339
7340         /* Avoid virtual calls to ctors if possible */
7341         if (mono_class_is_marshalbyref (cmethod->klass))
7342                 callvirt_this_arg = sp [0];
7343
7344         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7345                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7346                 CHECK_CFG_EXCEPTION;
7347         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7348                            mono_method_check_inlining (cfg, cmethod) &&
7349                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7350                 int costs;
7351
7352                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7353                         cfg->real_offset += 5;
7354
7355                         *inline_costs += costs - 5;
7356                 } else {
7357                         INLINE_FAILURE ("inline failure");
7358                         // FIXME-VT: Clean this up
7359                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7360                                 GSHAREDVT_FAILURE(*ip);
7361                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7362                 }
7363         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7364                 MonoInst *addr;
7365
7366                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7367
7368                 if (cfg->llvm_only) {
7369                         // FIXME: Avoid initializing vtable_arg
7370                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7371                 } else {
7372                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7373                 }
7374         } else if (context_used &&
7375                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7376                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7377                 MonoInst *cmethod_addr;
7378
7379                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7380
7381                 if (cfg->llvm_only) {
7382                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
7383                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7384                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7385                 } else {
7386                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7387                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7388
7389                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7390                 }
7391         } else {
7392                 INLINE_FAILURE ("ctor call");
7393                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7394                                                                                   callvirt_this_arg, NULL, vtable_arg);
7395         }
7396  exception_exit:
7397         return;
7398 }
7399
7400 static void
7401 emit_setret (MonoCompile *cfg, MonoInst *val)
7402 {
7403         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7404         MonoInst *ins;
7405
7406         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7407                 MonoInst *ret_addr;
7408
7409                 if (!cfg->vret_addr) {
7410                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7411                 } else {
7412                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7413
7414                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7415                         ins->klass = mono_class_from_mono_type (ret_type);
7416                 }
7417         } else {
7418 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7419                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7420                         MonoInst *iargs [1];
7421                         MonoInst *conv;
7422
7423                         iargs [0] = val;
7424                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7425                         mono_arch_emit_setret (cfg, cfg->method, conv);
7426                 } else {
7427                         mono_arch_emit_setret (cfg, cfg->method, val);
7428                 }
7429 #else
7430                 mono_arch_emit_setret (cfg, cfg->method, val);
7431 #endif
7432         }
7433 }
7434
7435 /*
7436  * mono_method_to_ir:
7437  *
7438  * Translate the .net IL into linear IR.
7439  *
7440  * @start_bblock: if not NULL, the starting basic block, used during inlining.
7441  * @end_bblock: if not NULL, the ending basic block, used during inlining.
7442  * @return_var: if not NULL, the place where the return value is stored, used during inlining.   
7443  * @inline_args: if not NULL, contains the arguments to the inline call
7444  * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise.
7445  * @is_virtual_call: whether this method is being called as a result of a call to callvirt
7446  *
7447  * This method is used to turn ECMA IL into Mono's internal Linear IR
7448  * reprensetation.  It is used both for entire methods, as well as
7449  * inlining existing methods.  In the former case, the @start_bblock,
7450  * @end_bblock, @return_var, @inline_args are all set to NULL, and the
7451  * inline_offset is set to zero.
7452  * 
7453  * Returns: the inline cost, or -1 if there was an error processing this method.
7454  */
7455 int
7456 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7457                    MonoInst *return_var, MonoInst **inline_args, 
7458                    guint inline_offset, gboolean is_virtual_call)
7459 {
7460         MonoError error;
7461         MonoInst *ins, **sp, **stack_start;
7462         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7463         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7464         MonoMethod *cmethod, *method_definition;
7465         MonoInst **arg_array;
7466         MonoMethodHeader *header;
7467         MonoImage *image;
7468         guint32 token, ins_flag;
7469         MonoClass *klass;
7470         MonoClass *constrained_class = NULL;
7471         unsigned char *ip, *end, *target, *err_pos;
7472         MonoMethodSignature *sig;
7473         MonoGenericContext *generic_context = NULL;
7474         MonoGenericContainer *generic_container = NULL;
7475         MonoType **param_types;
7476         int i, n, start_new_bblock, dreg;
7477         int num_calls = 0, inline_costs = 0;
7478         int breakpoint_id = 0;
7479         guint num_args;
7480         GSList *class_inits = NULL;
7481         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7482         int context_used;
7483         gboolean init_locals, seq_points, skip_dead_blocks;
7484         gboolean sym_seq_points = FALSE;
7485         MonoDebugMethodInfo *minfo;
7486         MonoBitSet *seq_point_locs = NULL;
7487         MonoBitSet *seq_point_set_locs = NULL;
7488
7489         cfg->disable_inline = is_jit_optimizer_disabled (method);
7490
7491         /* serialization and xdomain stuff may need access to private fields and methods */
7492         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7493         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7494         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7495         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7496         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7497         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7498
7499         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7500         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7501         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7502         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7503         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7504
7505         image = method->klass->image;
7506         header = mono_method_get_header_checked (method, &cfg->error);
7507         if (!header) {
7508                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7509                 goto exception_exit;
7510         } else {
7511                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7512         }
7513
7514         generic_container = mono_method_get_generic_container (method);
7515         sig = mono_method_signature (method);
7516         num_args = sig->hasthis + sig->param_count;
7517         ip = (unsigned char*)header->code;
7518         cfg->cil_start = ip;
7519         end = ip + header->code_size;
7520         cfg->stat_cil_code_size += header->code_size;
7521
7522         seq_points = cfg->gen_seq_points && cfg->method == method;
7523
7524         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7525                 /* We could hit a seq point before attaching to the JIT (#8338) */
7526                 seq_points = FALSE;
7527         }
7528
7529         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7530                 minfo = mono_debug_lookup_method (method);
7531                 if (minfo) {
7532                         MonoSymSeqPoint *sps;
7533                         int i, n_il_offsets;
7534
7535                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7536                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7537                         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);
7538                         sym_seq_points = TRUE;
7539                         for (i = 0; i < n_il_offsets; ++i) {
7540                                 if (sps [i].il_offset < header->code_size)
7541                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7542                         }
7543                         g_free (sps);
7544
7545                         MonoDebugMethodAsyncInfo* asyncMethod = mono_debug_lookup_method_async_debug_info (method);
7546                         if (asyncMethod) {
7547                                 for (i = 0; asyncMethod != NULL && i < asyncMethod->num_awaits; i++)
7548                                 {
7549                                         mono_bitset_set_fast (seq_point_locs, asyncMethod->resume_offsets[i]);
7550                                         mono_bitset_set_fast (seq_point_locs, asyncMethod->yield_offsets[i]);
7551                                 }
7552                                 mono_debug_free_method_async_debug_info (asyncMethod);
7553                         }
7554                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7555                         /* Methods without line number info like auto-generated property accessors */
7556                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7557                         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);
7558                         sym_seq_points = TRUE;
7559                 }
7560         }
7561
7562         /* 
7563          * Methods without init_locals set could cause asserts in various passes
7564          * (#497220). To work around this, we emit dummy initialization opcodes
7565          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7566          * on some platforms.
7567          */
7568         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
7569                 init_locals = header->init_locals;
7570         else
7571                 init_locals = TRUE;
7572
7573         method_definition = method;
7574         while (method_definition->is_inflated) {
7575                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7576                 method_definition = imethod->declaring;
7577         }
7578
7579         /* SkipVerification is not allowed if core-clr is enabled */
7580         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7581                 dont_verify = TRUE;
7582                 dont_verify_stloc = TRUE;
7583         }
7584
7585         if (sig->is_inflated)
7586                 generic_context = mono_method_get_context (method);
7587         else if (generic_container)
7588                 generic_context = &generic_container->context;
7589         cfg->generic_context = generic_context;
7590
7591         if (!cfg->gshared)
7592                 g_assert (!sig->has_type_parameters);
7593
7594         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7595                 g_assert (method->is_inflated);
7596                 g_assert (mono_method_get_context (method)->method_inst);
7597         }
7598         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7599                 g_assert (sig->generic_param_count);
7600
7601         if (cfg->method == method) {
7602                 cfg->real_offset = 0;
7603         } else {
7604                 cfg->real_offset = inline_offset;
7605         }
7606
7607         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7608         cfg->cil_offset_to_bb_len = header->code_size;
7609
7610         cfg->current_method = method;
7611
7612         if (cfg->verbose_level > 2)
7613                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7614
7615         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7616         if (sig->hasthis)
7617                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7618         for (n = 0; n < sig->param_count; ++n)
7619                 param_types [n + sig->hasthis] = sig->params [n];
7620         cfg->arg_types = param_types;
7621
7622         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7623         if (cfg->method == method) {
7624
7625                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7626                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7627
7628                 /* ENTRY BLOCK */
7629                 NEW_BBLOCK (cfg, start_bblock);
7630                 cfg->bb_entry = start_bblock;
7631                 start_bblock->cil_code = NULL;
7632                 start_bblock->cil_length = 0;
7633
7634                 /* EXIT BLOCK */
7635                 NEW_BBLOCK (cfg, end_bblock);
7636                 cfg->bb_exit = end_bblock;
7637                 end_bblock->cil_code = NULL;
7638                 end_bblock->cil_length = 0;
7639                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7640                 g_assert (cfg->num_bblocks == 2);
7641
7642                 arg_array = cfg->args;
7643
7644                 if (header->num_clauses) {
7645                         cfg->spvars = g_hash_table_new (NULL, NULL);
7646                         cfg->exvars = g_hash_table_new (NULL, NULL);
7647                 }
7648                 /* handle exception clauses */
7649                 for (i = 0; i < header->num_clauses; ++i) {
7650                         MonoBasicBlock *try_bb;
7651                         MonoExceptionClause *clause = &header->clauses [i];
7652                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7653
7654                         try_bb->real_offset = clause->try_offset;
7655                         try_bb->try_start = TRUE;
7656                         try_bb->region = ((i + 1) << 8) | clause->flags;
7657                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7658                         tblock->real_offset = clause->handler_offset;
7659                         tblock->flags |= BB_EXCEPTION_HANDLER;
7660
7661                         /*
7662                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7663                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7664                          */
7665                         if (COMPILE_LLVM (cfg))
7666                                 link_bblock (cfg, try_bb, tblock);
7667
7668                         if (*(ip + clause->handler_offset) == CEE_POP)
7669                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7670
7671                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7672                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7673                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7674                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7675                                 MONO_ADD_INS (tblock, ins);
7676
7677                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
7678                                         /* finally clauses already have a seq point */
7679                                         /* seq points for filter clauses are emitted below */
7680                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7681                                         MONO_ADD_INS (tblock, ins);
7682                                 }
7683
7684                                 /* todo: is a fault block unsafe to optimize? */
7685                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7686                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7687                         }
7688
7689                         /*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);
7690                           while (p < end) {
7691                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7692                           }*/
7693                         /* catch and filter blocks get the exception object on the stack */
7694                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7695                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7696
7697                                 /* mostly like handle_stack_args (), but just sets the input args */
7698                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7699                                 tblock->in_scount = 1;
7700                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7701                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7702
7703                                 cfg->cbb = tblock;
7704
7705 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7706                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7707                                 if (!cfg->compile_llvm) {
7708                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7709                                         ins->dreg = tblock->in_stack [0]->dreg;
7710                                         MONO_ADD_INS (tblock, ins);
7711                                 }
7712 #else
7713                                 MonoInst *dummy_use;
7714
7715                                 /* 
7716                                  * Add a dummy use for the exvar so its liveness info will be
7717                                  * correct.
7718                                  */
7719                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7720 #endif
7721
7722                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7723                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7724                                         MONO_ADD_INS (tblock, ins);
7725                                 }
7726                                 
7727                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7728                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7729                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7730                                         tblock->real_offset = clause->data.filter_offset;
7731                                         tblock->in_scount = 1;
7732                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7733                                         /* The filter block shares the exvar with the handler block */
7734                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7735                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7736                                         MONO_ADD_INS (tblock, ins);
7737                                 }
7738                         }
7739
7740                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7741                                         clause->data.catch_class &&
7742                                         cfg->gshared &&
7743                                         mono_class_check_context_used (clause->data.catch_class)) {
7744                                 /*
7745                                  * In shared generic code with catch
7746                                  * clauses containing type variables
7747                                  * the exception handling code has to
7748                                  * be able to get to the rgctx.
7749                                  * Therefore we have to make sure that
7750                                  * the vtable/mrgctx argument (for
7751                                  * static or generic methods) or the
7752                                  * "this" argument (for non-static
7753                                  * methods) are live.
7754                                  */
7755                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7756                                                 mini_method_get_context (method)->method_inst ||
7757                                                 method->klass->valuetype) {
7758                                         mono_get_vtable_var (cfg);
7759                                 } else {
7760                                         MonoInst *dummy_use;
7761
7762                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7763                                 }
7764                         }
7765                 }
7766         } else {
7767                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7768                 cfg->cbb = start_bblock;
7769                 cfg->args = arg_array;
7770                 mono_save_args (cfg, sig, inline_args);
7771         }
7772
7773         /* FIRST CODE BLOCK */
7774         NEW_BBLOCK (cfg, tblock);
7775         tblock->cil_code = ip;
7776         cfg->cbb = tblock;
7777         cfg->ip = ip;
7778
7779         ADD_BBLOCK (cfg, tblock);
7780
7781         if (cfg->method == method) {
7782                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7783                 if (breakpoint_id) {
7784                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7785                         MONO_ADD_INS (cfg->cbb, ins);
7786                 }
7787         }
7788
7789         /* we use a separate basic block for the initialization code */
7790         NEW_BBLOCK (cfg, init_localsbb);
7791         if (cfg->method == method)
7792                 cfg->bb_init = init_localsbb;
7793         init_localsbb->real_offset = cfg->real_offset;
7794         start_bblock->next_bb = init_localsbb;
7795         init_localsbb->next_bb = cfg->cbb;
7796         link_bblock (cfg, start_bblock, init_localsbb);
7797         link_bblock (cfg, init_localsbb, cfg->cbb);
7798                 
7799         cfg->cbb = init_localsbb;
7800
7801         if (cfg->gsharedvt && cfg->method == method) {
7802                 MonoGSharedVtMethodInfo *info;
7803                 MonoInst *var, *locals_var;
7804                 int dreg;
7805
7806                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7807                 info->method = cfg->method;
7808                 info->count_entries = 16;
7809                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7810                 cfg->gsharedvt_info = info;
7811
7812                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7813                 /* prevent it from being register allocated */
7814                 //var->flags |= MONO_INST_VOLATILE;
7815                 cfg->gsharedvt_info_var = var;
7816
7817                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7818                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7819
7820                 /* Allocate locals */
7821                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7822                 /* prevent it from being register allocated */
7823                 //locals_var->flags |= MONO_INST_VOLATILE;
7824                 cfg->gsharedvt_locals_var = locals_var;
7825
7826                 dreg = alloc_ireg (cfg);
7827                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7828
7829                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7830                 ins->dreg = locals_var->dreg;
7831                 ins->sreg1 = dreg;
7832                 MONO_ADD_INS (cfg->cbb, ins);
7833                 cfg->gsharedvt_locals_var_ins = ins;
7834                 
7835                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7836                 /*
7837                 if (init_locals)
7838                         ins->flags |= MONO_INST_INIT;
7839                 */
7840         }
7841
7842         if (mono_security_core_clr_enabled ()) {
7843                 /* check if this is native code, e.g. an icall or a p/invoke */
7844                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7845                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7846                         if (wrapped) {
7847                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7848                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7849
7850                                 /* if this ia a native call then it can only be JITted from platform code */
7851                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7852                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7853                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7854                                                         mono_get_exception_method_access ();
7855                                                 emit_throw_exception (cfg, ex);
7856                                         }
7857                                 }
7858                         }
7859                 }
7860         }
7861
7862         CHECK_CFG_EXCEPTION;
7863
7864         if (header->code_size == 0)
7865                 UNVERIFIED;
7866
7867         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7868                 ip = err_pos;
7869                 UNVERIFIED;
7870         }
7871
7872         if (cfg->method == method)
7873                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
7874
7875         for (n = 0; n < header->num_locals; ++n) {
7876                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7877                         UNVERIFIED;
7878         }
7879         class_inits = NULL;
7880
7881         /* We force the vtable variable here for all shared methods
7882            for the possibility that they might show up in a stack
7883            trace where their exact instantiation is needed. */
7884         if (cfg->gshared && method == cfg->method) {
7885                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7886                                 mini_method_get_context (method)->method_inst ||
7887                                 method->klass->valuetype) {
7888                         mono_get_vtable_var (cfg);
7889                 } else {
7890                         /* FIXME: Is there a better way to do this?
7891                            We need the variable live for the duration
7892                            of the whole method. */
7893                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7894                 }
7895         }
7896
7897         /* add a check for this != NULL to inlined methods */
7898         if (is_virtual_call) {
7899                 MonoInst *arg_ins;
7900
7901                 NEW_ARGLOAD (cfg, arg_ins, 0);
7902                 MONO_ADD_INS (cfg->cbb, arg_ins);
7903                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7904         }
7905
7906         skip_dead_blocks = !dont_verify;
7907         if (skip_dead_blocks) {
7908                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
7909                 CHECK_CFG_ERROR;
7910                 g_assert (bb);
7911         }
7912
7913         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7914         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7915
7916         ins_flag = 0;
7917         start_new_bblock = 0;
7918         while (ip < end) {
7919                 if (cfg->method == method)
7920                         cfg->real_offset = ip - header->code;
7921                 else
7922                         cfg->real_offset = inline_offset;
7923                 cfg->ip = ip;
7924
7925                 context_used = 0;
7926
7927                 if (start_new_bblock) {
7928                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
7929                         if (start_new_bblock == 2) {
7930                                 g_assert (ip == tblock->cil_code);
7931                         } else {
7932                                 GET_BBLOCK (cfg, tblock, ip);
7933                         }
7934                         cfg->cbb->next_bb = tblock;
7935                         cfg->cbb = tblock;
7936                         start_new_bblock = 0;
7937                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
7938                                 if (cfg->verbose_level > 3)
7939                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7940                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7941                                 *sp++ = ins;
7942                         }
7943                         if (class_inits)
7944                                 g_slist_free (class_inits);
7945                         class_inits = NULL;
7946                 } else {
7947                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
7948                                 link_bblock (cfg, cfg->cbb, tblock);
7949                                 if (sp != stack_start) {
7950                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7951                                         sp = stack_start;
7952                                         CHECK_UNVERIFIABLE (cfg);
7953                                 }
7954                                 cfg->cbb->next_bb = tblock;
7955                                 cfg->cbb = tblock;
7956                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
7957                                         if (cfg->verbose_level > 3)
7958                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7959                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7960                                         *sp++ = ins;
7961                                 }
7962                                 g_slist_free (class_inits);
7963                                 class_inits = NULL;
7964                         }
7965                 }
7966
7967                 if (skip_dead_blocks) {
7968                         int ip_offset = ip - header->code;
7969
7970                         if (ip_offset == bb->end)
7971                                 bb = bb->next;
7972
7973                         if (bb->dead) {
7974                                 int op_size = mono_opcode_size (ip, end);
7975                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7976
7977                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7978
7979                                 if (ip_offset + op_size == bb->end) {
7980                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7981                                         MONO_ADD_INS (cfg->cbb, ins);
7982                                         start_new_bblock = 1;
7983                                 }
7984
7985                                 ip += op_size;
7986                                 continue;
7987                         }
7988                 }
7989                 /*
7990                  * Sequence points are points where the debugger can place a breakpoint.
7991                  * Currently, we generate these automatically at points where the IL
7992                  * stack is empty.
7993                  */
7994                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7995                         /*
7996                          * Make methods interruptable at the beginning, and at the targets of
7997                          * backward branches.
7998                          * Also, do this at the start of every bblock in methods with clauses too,
7999                          * to be able to handle instructions with inprecise control flow like
8000                          * throw/endfinally.
8001                          * Backward branches are handled at the end of method-to-ir ().
8002                          */
8003                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8004                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8005
8006                         /* Avoid sequence points on empty IL like .volatile */
8007                         // FIXME: Enable this
8008                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8009                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8010                         if ((sp != stack_start) && !sym_seq_point)
8011                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8012                         MONO_ADD_INS (cfg->cbb, ins);
8013
8014                         if (sym_seq_points)
8015                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8016                 }
8017
8018                 cfg->cbb->real_offset = cfg->real_offset;
8019
8020                 if ((cfg->method == method) && cfg->coverage_info) {
8021                         guint32 cil_offset = ip - header->code;
8022                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8023
8024                         /* TODO: Use an increment here */
8025 #if defined(TARGET_X86)
8026                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8027                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8028                         ins->inst_imm = 1;
8029                         MONO_ADD_INS (cfg->cbb, ins);
8030 #else
8031                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8032                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8033 #endif
8034                 }
8035
8036                 if (cfg->verbose_level > 3)
8037                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8038
8039                 switch (*ip) {
8040                 case CEE_NOP:
8041                         if (seq_points && !sym_seq_points && sp != stack_start) {
8042                                 /*
8043                                  * The C# compiler uses these nops to notify the JIT that it should
8044                                  * insert seq points.
8045                                  */
8046                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8047                                 MONO_ADD_INS (cfg->cbb, ins);
8048                         }
8049                         if (cfg->keep_cil_nops)
8050                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8051                         else
8052                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8053                         ip++;
8054                         MONO_ADD_INS (cfg->cbb, ins);
8055                         break;
8056                 case CEE_BREAK:
8057                         if (should_insert_brekpoint (cfg->method)) {
8058                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8059                         } else {
8060                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8061                         }
8062                         ip++;
8063                         MONO_ADD_INS (cfg->cbb, ins);
8064                         break;
8065                 case CEE_LDARG_0:
8066                 case CEE_LDARG_1:
8067                 case CEE_LDARG_2:
8068                 case CEE_LDARG_3:
8069                         CHECK_STACK_OVF (1);
8070                         n = (*ip)-CEE_LDARG_0;
8071                         CHECK_ARG (n);
8072                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8073                         ip++;
8074                         *sp++ = ins;
8075                         break;
8076                 case CEE_LDLOC_0:
8077                 case CEE_LDLOC_1:
8078                 case CEE_LDLOC_2:
8079                 case CEE_LDLOC_3:
8080                         CHECK_STACK_OVF (1);
8081                         n = (*ip)-CEE_LDLOC_0;
8082                         CHECK_LOCAL (n);
8083                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8084                         ip++;
8085                         *sp++ = ins;
8086                         break;
8087                 case CEE_STLOC_0:
8088                 case CEE_STLOC_1:
8089                 case CEE_STLOC_2:
8090                 case CEE_STLOC_3: {
8091                         CHECK_STACK (1);
8092                         n = (*ip)-CEE_STLOC_0;
8093                         CHECK_LOCAL (n);
8094                         --sp;
8095                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8096                                 UNVERIFIED;
8097                         emit_stloc_ir (cfg, sp, header, n);
8098                         ++ip;
8099                         inline_costs += 1;
8100                         break;
8101                         }
8102                 case CEE_LDARG_S:
8103                         CHECK_OPSIZE (2);
8104                         CHECK_STACK_OVF (1);
8105                         n = ip [1];
8106                         CHECK_ARG (n);
8107                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8108                         *sp++ = ins;
8109                         ip += 2;
8110                         break;
8111                 case CEE_LDARGA_S:
8112                         CHECK_OPSIZE (2);
8113                         CHECK_STACK_OVF (1);
8114                         n = ip [1];
8115                         CHECK_ARG (n);
8116                         NEW_ARGLOADA (cfg, ins, n);
8117                         MONO_ADD_INS (cfg->cbb, ins);
8118                         *sp++ = ins;
8119                         ip += 2;
8120                         break;
8121                 case CEE_STARG_S:
8122                         CHECK_OPSIZE (2);
8123                         CHECK_STACK (1);
8124                         --sp;
8125                         n = ip [1];
8126                         CHECK_ARG (n);
8127                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8128                                 UNVERIFIED;
8129                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8130                         ip += 2;
8131                         break;
8132                 case CEE_LDLOC_S:
8133                         CHECK_OPSIZE (2);
8134                         CHECK_STACK_OVF (1);
8135                         n = ip [1];
8136                         CHECK_LOCAL (n);
8137                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8138                         *sp++ = ins;
8139                         ip += 2;
8140                         break;
8141                 case CEE_LDLOCA_S: {
8142                         unsigned char *tmp_ip;
8143                         CHECK_OPSIZE (2);
8144                         CHECK_STACK_OVF (1);
8145                         CHECK_LOCAL (ip [1]);
8146
8147                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8148                                 ip = tmp_ip;
8149                                 inline_costs += 1;
8150                                 break;
8151                         }
8152
8153                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8154                         *sp++ = ins;
8155                         ip += 2;
8156                         break;
8157                 }
8158                 case CEE_STLOC_S:
8159                         CHECK_OPSIZE (2);
8160                         CHECK_STACK (1);
8161                         --sp;
8162                         CHECK_LOCAL (ip [1]);
8163                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8164                                 UNVERIFIED;
8165                         emit_stloc_ir (cfg, sp, header, ip [1]);
8166                         ip += 2;
8167                         inline_costs += 1;
8168                         break;
8169                 case CEE_LDNULL:
8170                         CHECK_STACK_OVF (1);
8171                         EMIT_NEW_PCONST (cfg, ins, NULL);
8172                         ins->type = STACK_OBJ;
8173                         ++ip;
8174                         *sp++ = ins;
8175                         break;
8176                 case CEE_LDC_I4_M1:
8177                         CHECK_STACK_OVF (1);
8178                         EMIT_NEW_ICONST (cfg, ins, -1);
8179                         ++ip;
8180                         *sp++ = ins;
8181                         break;
8182                 case CEE_LDC_I4_0:
8183                 case CEE_LDC_I4_1:
8184                 case CEE_LDC_I4_2:
8185                 case CEE_LDC_I4_3:
8186                 case CEE_LDC_I4_4:
8187                 case CEE_LDC_I4_5:
8188                 case CEE_LDC_I4_6:
8189                 case CEE_LDC_I4_7:
8190                 case CEE_LDC_I4_8:
8191                         CHECK_STACK_OVF (1);
8192                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8193                         ++ip;
8194                         *sp++ = ins;
8195                         break;
8196                 case CEE_LDC_I4_S:
8197                         CHECK_OPSIZE (2);
8198                         CHECK_STACK_OVF (1);
8199                         ++ip;
8200                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8201                         ++ip;
8202                         *sp++ = ins;
8203                         break;
8204                 case CEE_LDC_I4:
8205                         CHECK_OPSIZE (5);
8206                         CHECK_STACK_OVF (1);
8207                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8208                         ip += 5;
8209                         *sp++ = ins;
8210                         break;
8211                 case CEE_LDC_I8:
8212                         CHECK_OPSIZE (9);
8213                         CHECK_STACK_OVF (1);
8214                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8215                         ins->type = STACK_I8;
8216                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8217                         ++ip;
8218                         ins->inst_l = (gint64)read64 (ip);
8219                         MONO_ADD_INS (cfg->cbb, ins);
8220                         ip += 8;
8221                         *sp++ = ins;
8222                         break;
8223                 case CEE_LDC_R4: {
8224                         float *f;
8225                         gboolean use_aotconst = FALSE;
8226
8227 #ifdef TARGET_POWERPC
8228                         /* FIXME: Clean this up */
8229                         if (cfg->compile_aot)
8230                                 use_aotconst = TRUE;
8231 #endif
8232
8233                         /* FIXME: we should really allocate this only late in the compilation process */
8234                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8235                         CHECK_OPSIZE (5);
8236                         CHECK_STACK_OVF (1);
8237
8238                         if (use_aotconst) {
8239                                 MonoInst *cons;
8240                                 int dreg;
8241
8242                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8243
8244                                 dreg = alloc_freg (cfg);
8245                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8246                                 ins->type = cfg->r4_stack_type;
8247                         } else {
8248                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8249                                 ins->type = cfg->r4_stack_type;
8250                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8251                                 ins->inst_p0 = f;
8252                                 MONO_ADD_INS (cfg->cbb, ins);
8253                         }
8254                         ++ip;
8255                         readr4 (ip, f);
8256                         ip += 4;
8257                         *sp++ = ins;                    
8258                         break;
8259                 }
8260                 case CEE_LDC_R8: {
8261                         double *d;
8262                         gboolean use_aotconst = FALSE;
8263
8264 #ifdef TARGET_POWERPC
8265                         /* FIXME: Clean this up */
8266                         if (cfg->compile_aot)
8267                                 use_aotconst = TRUE;
8268 #endif
8269
8270                         /* FIXME: we should really allocate this only late in the compilation process */
8271                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8272                         CHECK_OPSIZE (9);
8273                         CHECK_STACK_OVF (1);
8274
8275                         if (use_aotconst) {
8276                                 MonoInst *cons;
8277                                 int dreg;
8278
8279                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8280
8281                                 dreg = alloc_freg (cfg);
8282                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8283                                 ins->type = STACK_R8;
8284                         } else {
8285                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8286                                 ins->type = STACK_R8;
8287                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8288                                 ins->inst_p0 = d;
8289                                 MONO_ADD_INS (cfg->cbb, ins);
8290                         }
8291                         ++ip;
8292                         readr8 (ip, d);
8293                         ip += 8;
8294                         *sp++ = ins;
8295                         break;
8296                 }
8297                 case CEE_DUP: {
8298                         MonoInst *temp, *store;
8299                         CHECK_STACK (1);
8300                         CHECK_STACK_OVF (1);
8301                         sp--;
8302                         ins = *sp;
8303
8304                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8305                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8306
8307                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8308                         *sp++ = ins;
8309
8310                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8311                         *sp++ = ins;
8312
8313                         ++ip;
8314                         inline_costs += 2;
8315                         break;
8316                 }
8317                 case CEE_POP:
8318                         CHECK_STACK (1);
8319                         ip++;
8320                         --sp;
8321
8322 #ifdef TARGET_X86
8323                         if (sp [0]->type == STACK_R8)
8324                                 /* we need to pop the value from the x86 FP stack */
8325                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8326 #endif
8327                         break;
8328                 case CEE_JMP: {
8329                         MonoCallInst *call;
8330                         MonoMethodSignature *fsig;
8331                         int i, n;
8332
8333                         INLINE_FAILURE ("jmp");
8334                         GSHAREDVT_FAILURE (*ip);
8335
8336                         CHECK_OPSIZE (5);
8337                         if (stack_start != sp)
8338                                 UNVERIFIED;
8339                         token = read32 (ip + 1);
8340                         /* FIXME: check the signature matches */
8341                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8342                         CHECK_CFG_ERROR;
8343  
8344                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8345                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8346
8347                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8348
8349                         fsig = mono_method_signature (cmethod);
8350                         n = fsig->param_count + fsig->hasthis;
8351                         if (cfg->llvm_only) {
8352                                 MonoInst **args;
8353
8354                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8355                                 for (i = 0; i < n; ++i)
8356                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8357                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8358                                 /*
8359                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8360                                  * have to emit a normal return since llvm expects it.
8361                                  */
8362                                 if (cfg->ret)
8363                                         emit_setret (cfg, ins);
8364                                 MONO_INST_NEW (cfg, ins, OP_BR);
8365                                 ins->inst_target_bb = end_bblock;
8366                                 MONO_ADD_INS (cfg->cbb, ins);
8367                                 link_bblock (cfg, cfg->cbb, end_bblock);
8368                                 ip += 5;
8369                                 break;
8370                         } else if (cfg->backend->have_op_tail_call) {
8371                                 /* Handle tail calls similarly to calls */
8372                                 DISABLE_AOT (cfg);
8373
8374                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8375                                 call->method = cmethod;
8376                                 call->tail_call = TRUE;
8377                                 call->signature = mono_method_signature (cmethod);
8378                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8379                                 call->inst.inst_p0 = cmethod;
8380                                 for (i = 0; i < n; ++i)
8381                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8382
8383                                 if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
8384                                         call->vret_var = cfg->vret_addr;
8385
8386                                 mono_arch_emit_call (cfg, call);
8387                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8388                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8389                         } else {
8390                                 for (i = 0; i < num_args; ++i)
8391                                         /* Prevent arguments from being optimized away */
8392                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8393
8394                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8395                                 ins = (MonoInst*)call;
8396                                 ins->inst_p0 = cmethod;
8397                                 MONO_ADD_INS (cfg->cbb, ins);
8398                         }
8399
8400                         ip += 5;
8401                         start_new_bblock = 1;
8402                         break;
8403                 }
8404                 case CEE_CALLI: {
8405                         MonoInst *addr;
8406                         MonoMethodSignature *fsig;
8407
8408                         CHECK_OPSIZE (5);
8409                         token = read32 (ip + 1);
8410
8411                         ins = NULL;
8412
8413                         //GSHAREDVT_FAILURE (*ip);
8414                         cmethod = NULL;
8415                         CHECK_STACK (1);
8416                         --sp;
8417                         addr = *sp;
8418                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
8419                         CHECK_CFG_ERROR;
8420
8421                         if (method->dynamic && fsig->pinvoke) {
8422                                 MonoInst *args [3];
8423
8424                                 /*
8425                                  * This is a call through a function pointer using a pinvoke
8426                                  * signature. Have to create a wrapper and call that instead.
8427                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8428                                  * instead based on the signature.
8429                                  */
8430                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8431                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8432                                 args [2] = addr;
8433                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8434                         }
8435
8436                         n = fsig->param_count + fsig->hasthis;
8437
8438                         CHECK_STACK (n);
8439
8440                         //g_assert (!virtual_ || fsig->hasthis);
8441
8442                         sp -= n;
8443
8444                         inline_costs += 10 * num_calls++;
8445
8446                         /*
8447                          * Making generic calls out of gsharedvt methods.
8448                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8449                          * patching gshared method addresses into a gsharedvt method.
8450                          */
8451                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8452                                 /*
8453                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8454                                  */
8455                                 MonoInst *callee = addr;
8456
8457                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8458                                         /* Not tested */
8459                                         GSHAREDVT_FAILURE (*ip);
8460
8461                                 if (cfg->llvm_only)
8462                                         // FIXME:
8463                                         GSHAREDVT_FAILURE (*ip);
8464
8465                                 addr = emit_get_rgctx_sig (cfg, context_used,
8466                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8467                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8468                                 goto calli_end;
8469                         }
8470
8471                         /* Prevent inlining of methods with indirect calls */
8472                         INLINE_FAILURE ("indirect call");
8473
8474                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8475                                 MonoJumpInfoType info_type;
8476                                 gpointer info_data;
8477
8478                                 /*
8479                                  * Instead of emitting an indirect call, emit a direct call
8480                                  * with the contents of the aotconst as the patch info.
8481                                  */
8482                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8483                                         info_type = (MonoJumpInfoType)addr->inst_c1;
8484                                         info_data = addr->inst_p0;
8485                                 } else {
8486                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
8487                                         info_data = addr->inst_right->inst_left;
8488                                 }
8489
8490                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
8491                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
8492                                         NULLIFY_INS (addr);
8493                                         goto calli_end;
8494                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8495                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8496                                         NULLIFY_INS (addr);
8497                                         goto calli_end;
8498                                 }
8499                         }
8500                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8501
8502                         calli_end:
8503
8504                         /* End of call, INS should contain the result of the call, if any */
8505
8506                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8507                                 g_assert (ins);
8508                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8509                         }
8510
8511                         CHECK_CFG_EXCEPTION;
8512
8513                         ip += 5;
8514                         ins_flag = 0;
8515                         constrained_class = NULL;
8516                         break;
8517                 }
8518                 case CEE_CALL:
8519                 case CEE_CALLVIRT: {
8520                         MonoInst *addr = NULL;
8521                         MonoMethodSignature *fsig = NULL;
8522                         int array_rank = 0;
8523                         int virtual_ = *ip == CEE_CALLVIRT;
8524                         gboolean pass_imt_from_rgctx = FALSE;
8525                         MonoInst *imt_arg = NULL;
8526                         MonoInst *keep_this_alive = NULL;
8527                         gboolean pass_vtable = FALSE;
8528                         gboolean pass_mrgctx = FALSE;
8529                         MonoInst *vtable_arg = NULL;
8530                         gboolean check_this = FALSE;
8531                         gboolean supported_tail_call = FALSE;
8532                         gboolean tail_call = FALSE;
8533                         gboolean need_seq_point = FALSE;
8534                         guint32 call_opcode = *ip;
8535                         gboolean emit_widen = TRUE;
8536                         gboolean push_res = TRUE;
8537                         gboolean skip_ret = FALSE;
8538                         gboolean delegate_invoke = FALSE;
8539                         gboolean direct_icall = FALSE;
8540                         gboolean constrained_partial_call = FALSE;
8541                         MonoMethod *cil_method;
8542
8543                         CHECK_OPSIZE (5);
8544                         token = read32 (ip + 1);
8545
8546                         ins = NULL;
8547
8548                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8549                         CHECK_CFG_ERROR;
8550
8551                         cil_method = cmethod;
8552                                 
8553                         if (constrained_class) {
8554                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8555                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8556                                                 g_assert (!cmethod->klass->valuetype);
8557                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8558                                                         constrained_partial_call = TRUE;
8559                                         }
8560                                 }
8561
8562                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8563                                         if (cfg->verbose_level > 2)
8564                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8565                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8566                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8567                                                   cfg->gshared)) {
8568                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8569                                                 CHECK_CFG_ERROR;
8570                                         }
8571                                 } else {
8572                                         if (cfg->verbose_level > 2)
8573                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8574
8575                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8576                                                 /* 
8577                                                  * This is needed since get_method_constrained can't find 
8578                                                  * the method in klass representing a type var.
8579                                                  * The type var is guaranteed to be a reference type in this
8580                                                  * case.
8581                                                  */
8582                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8583                                                         g_assert (!cmethod->klass->valuetype);
8584                                         } else {
8585                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8586                                                 CHECK_CFG_ERROR;
8587                                         }
8588                                 }
8589
8590                                 if (constrained_class->enumtype && !strcmp (cmethod->name, "GetHashCode")) {
8591                                         /* Use the corresponding method from the base type to avoid boxing */
8592                                         MonoType *base_type = mono_class_enum_basetype (constrained_class);
8593                                         g_assert (base_type);
8594                                         constrained_class = mono_class_from_mono_type (base_type);
8595                                         cmethod = mono_class_get_method_from_name (constrained_class, cmethod->name, 0);
8596                                         g_assert (cmethod);
8597                                 }
8598                         }
8599                                         
8600                         if (!dont_verify && !cfg->skip_visibility) {
8601                                 MonoMethod *target_method = cil_method;
8602                                 if (method->is_inflated) {
8603                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
8604                                         CHECK_CFG_ERROR;
8605                                 }
8606                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8607                                         !mono_method_can_access_method (method, cil_method))
8608                                         emit_method_access_failure (cfg, method, cil_method);
8609                         }
8610
8611                         if (mono_security_core_clr_enabled ())
8612                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8613
8614                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8615                                 /* MS.NET seems to silently convert this to a callvirt */
8616                                 virtual_ = 1;
8617
8618                         {
8619                                 /*
8620                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8621                                  * converts to a callvirt.
8622                                  *
8623                                  * tests/bug-515884.il is an example of this behavior
8624                                  */
8625                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8626                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8627                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8628                                         virtual_ = 1;
8629                         }
8630
8631                         if (!cmethod->klass->inited)
8632                                 if (!mono_class_init (cmethod->klass))
8633                                         TYPE_LOAD_ERROR (cmethod->klass);
8634
8635                         fsig = mono_method_signature (cmethod);
8636                         if (!fsig)
8637                                 LOAD_ERROR;
8638                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8639                                 mini_class_is_system_array (cmethod->klass)) {
8640                                 array_rank = cmethod->klass->rank;
8641                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8642                                 direct_icall = TRUE;
8643                         } else if (fsig->pinvoke) {
8644                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8645                                 fsig = mono_method_signature (wrapper);
8646                         } else if (constrained_class) {
8647                         } else {
8648                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8649                                 CHECK_CFG_ERROR;
8650                         }
8651
8652                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
8653                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
8654
8655                         /* See code below */
8656                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8657                                 MonoBasicBlock *tbb;
8658
8659                                 GET_BBLOCK (cfg, tbb, ip + 5);
8660                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8661                                         /*
8662                                          * We want to extend the try block to cover the call, but we can't do it if the
8663                                          * call is made directly since its followed by an exception check.
8664                                          */
8665                                         direct_icall = FALSE;
8666                                 }
8667                         }
8668
8669                         mono_save_token_info (cfg, image, token, cil_method);
8670
8671                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8672                                 need_seq_point = TRUE;
8673
8674                         /* Don't support calls made using type arguments for now */
8675                         /*
8676                           if (cfg->gsharedvt) {
8677                           if (mini_is_gsharedvt_signature (fsig))
8678                           GSHAREDVT_FAILURE (*ip);
8679                           }
8680                         */
8681
8682                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8683                                 g_assert_not_reached ();
8684
8685                         n = fsig->param_count + fsig->hasthis;
8686
8687                         if (!cfg->gshared && mono_class_is_gtd (cmethod->klass))
8688                                 UNVERIFIED;
8689
8690                         if (!cfg->gshared)
8691                                 g_assert (!mono_method_check_context_used (cmethod));
8692
8693                         CHECK_STACK (n);
8694
8695                         //g_assert (!virtual_ || fsig->hasthis);
8696
8697                         sp -= n;
8698
8699                         /*
8700                          * We have the `constrained.' prefix opcode.
8701                          */
8702                         if (constrained_class) {
8703                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8704                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8705                                                 /* The 'Own method' case below */
8706                                         } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) {
8707                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8708                                         } else {
8709                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8710                                                 CHECK_CFG_EXCEPTION;
8711                                                 g_assert (ins);
8712                                                 goto call_end;
8713                                         }
8714                                 }
8715
8716                                 if (constrained_partial_call) {
8717                                         gboolean need_box = TRUE;
8718
8719                                         /*
8720                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8721                                          * called method is not known at compile time either. The called method could end up being
8722                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8723                                          * to box the receiver.
8724                                          * A simple solution would be to box always and make a normal virtual call, but that would
8725                                          * be bad performance wise.
8726                                          */
8727                                         if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) {
8728                                                 /*
8729                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8730                                                  */
8731                                                 need_box = FALSE;
8732                                         }
8733
8734                                         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)) {
8735                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8736                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8737                                                 ins->klass = constrained_class;
8738                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8739                                                 CHECK_CFG_EXCEPTION;
8740                                         } else if (need_box) {
8741                                                 MonoInst *box_type;
8742                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8743                                                 MonoInst *nonbox_call;
8744
8745                                                 /*
8746                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8747                                                  * if needed.
8748                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8749                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8750                                                  */
8751                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8752
8753                                                 NEW_BBLOCK (cfg, is_ref_bb);
8754                                                 NEW_BBLOCK (cfg, end_bb);
8755
8756                                                 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);
8757                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
8758                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
8759
8760                                                 /* Non-ref case */
8761                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8762
8763                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8764
8765                                                 /* Ref case */
8766                                                 MONO_START_BB (cfg, is_ref_bb);
8767                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8768                                                 ins->klass = constrained_class;
8769                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8770                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8771
8772                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8773
8774                                                 MONO_START_BB (cfg, end_bb);
8775                                                 cfg->cbb = end_bb;
8776
8777                                                 nonbox_call->dreg = ins->dreg;
8778                                                 goto call_end;
8779                                         } else {
8780                                                 g_assert (mono_class_is_interface (cmethod->klass));
8781                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8782                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8783                                                 goto call_end;
8784                                         }
8785                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8786                                         /*
8787                                          * The type parameter is instantiated as a valuetype,
8788                                          * but that type doesn't override the method we're
8789                                          * calling, so we need to box `this'.
8790                                          */
8791                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8792                                         ins->klass = constrained_class;
8793                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8794                                         CHECK_CFG_EXCEPTION;
8795                                 } else if (!constrained_class->valuetype) {
8796                                         int dreg = alloc_ireg_ref (cfg);
8797
8798                                         /*
8799                                          * The type parameter is instantiated as a reference
8800                                          * type.  We have a managed pointer on the stack, so
8801                                          * we need to dereference it here.
8802                                          */
8803                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8804                                         ins->type = STACK_OBJ;
8805                                         sp [0] = ins;
8806                                 } else {
8807                                         if (cmethod->klass->valuetype) {
8808                                                 /* Own method */
8809                                         } else {
8810                                                 /* Interface method */
8811                                                 int ioffset, slot;
8812
8813                                                 mono_class_setup_vtable (constrained_class);
8814                                                 CHECK_TYPELOAD (constrained_class);
8815                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8816                                                 if (ioffset == -1)
8817                                                         TYPE_LOAD_ERROR (constrained_class);
8818                                                 slot = mono_method_get_vtable_slot (cmethod);
8819                                                 if (slot == -1)
8820                                                         TYPE_LOAD_ERROR (cmethod->klass);
8821                                                 cmethod = constrained_class->vtable [ioffset + slot];
8822
8823                                                 if (cmethod->klass == mono_defaults.enum_class) {
8824                                                         /* Enum implements some interfaces, so treat this as the first case */
8825                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8826                                                         ins->klass = constrained_class;
8827                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8828                                                         CHECK_CFG_EXCEPTION;
8829                                                 }
8830                                         }
8831                                         virtual_ = 0;
8832                                 }
8833                                 constrained_class = NULL;
8834                         }
8835
8836                         if (check_call_signature (cfg, fsig, sp))
8837                                 UNVERIFIED;
8838
8839                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8840                                 delegate_invoke = TRUE;
8841
8842                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8843                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8844                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8845                                         emit_widen = FALSE;
8846                                 }
8847
8848                                 goto call_end;
8849                         }
8850
8851                         /* 
8852                          * If the callee is a shared method, then its static cctor
8853                          * might not get called after the call was patched.
8854                          */
8855                         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)) {
8856                                 emit_class_init (cfg, cmethod->klass);
8857                                 CHECK_TYPELOAD (cmethod->klass);
8858                         }
8859
8860                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8861
8862                         if (cfg->gshared) {
8863                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8864
8865                                 context_used = mini_method_check_context_used (cfg, cmethod);
8866
8867                                 if (context_used && mono_class_is_interface (cmethod->klass)) {
8868                                         /* Generic method interface
8869                                            calls are resolved via a
8870                                            helper function and don't
8871                                            need an imt. */
8872                                         if (!cmethod_context || !cmethod_context->method_inst)
8873                                                 pass_imt_from_rgctx = TRUE;
8874                                 }
8875
8876                                 /*
8877                                  * If a shared method calls another
8878                                  * shared method then the caller must
8879                                  * have a generic sharing context
8880                                  * because the magic trampoline
8881                                  * requires it.  FIXME: We shouldn't
8882                                  * have to force the vtable/mrgctx
8883                                  * variable here.  Instead there
8884                                  * should be a flag in the cfg to
8885                                  * request a generic sharing context.
8886                                  */
8887                                 if (context_used &&
8888                                                 ((cfg->method->flags & METHOD_ATTRIBUTE_STATIC) || cfg->method->klass->valuetype))
8889                                         mono_get_vtable_var (cfg);
8890                         }
8891
8892                         if (pass_vtable) {
8893                                 if (context_used) {
8894                                         vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8895                                 } else {
8896                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8897
8898                                         CHECK_TYPELOAD (cmethod->klass);
8899                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8900                                 }
8901                         }
8902
8903                         if (pass_mrgctx) {
8904                                 g_assert (!vtable_arg);
8905
8906                                 if (!cfg->compile_aot) {
8907                                         /* 
8908                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8909                                          * for type load errors before.
8910                                          */
8911                                         mono_class_setup_vtable (cmethod->klass);
8912                                         CHECK_TYPELOAD (cmethod->klass);
8913                                 }
8914
8915                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8916
8917                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8918                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8919                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8920                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8921                                         if (virtual_)
8922                                                 check_this = TRUE;
8923                                         virtual_ = 0;
8924                                 }
8925                         }
8926
8927                         if (pass_imt_from_rgctx) {
8928                                 g_assert (!pass_vtable);
8929
8930                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8931                                         cmethod, MONO_RGCTX_INFO_METHOD);
8932                         }
8933
8934                         if (check_this)
8935                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8936
8937                         /* Calling virtual generic methods */
8938                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
8939                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8940                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8941                             fsig->generic_param_count && 
8942                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
8943                                 !cfg->llvm_only) {
8944                                 MonoInst *this_temp, *this_arg_temp, *store;
8945                                 MonoInst *iargs [4];
8946
8947                                 g_assert (fsig->is_inflated);
8948
8949                                 /* Prevent inlining of methods that contain indirect calls */
8950                                 INLINE_FAILURE ("virtual generic call");
8951
8952                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8953                                         GSHAREDVT_FAILURE (*ip);
8954
8955                                 if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
8956                                         g_assert (!imt_arg);
8957                                         if (!context_used)
8958                                                 g_assert (cmethod->is_inflated);
8959                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8960                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8961                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8962                                 } else {
8963                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8964                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8965                                         MONO_ADD_INS (cfg->cbb, store);
8966
8967                                         /* FIXME: This should be a managed pointer */
8968                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8969
8970                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8971                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8972                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8973                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8974                                         addr = mono_emit_jit_icall (cfg,
8975                                                                                                 mono_helper_compile_generic_method, iargs);
8976
8977                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8978
8979                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8980                                 }
8981
8982                                 goto call_end;
8983                         }
8984
8985                         /*
8986                          * Implement a workaround for the inherent races involved in locking:
8987                          * Monitor.Enter ()
8988                          * try {
8989                          * } finally {
8990                          *    Monitor.Exit ()
8991                          * }
8992                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8993                          * try block, the Exit () won't be executed, see:
8994                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8995                          * To work around this, we extend such try blocks to include the last x bytes
8996                          * of the Monitor.Enter () call.
8997                          */
8998                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8999                                 MonoBasicBlock *tbb;
9000
9001                                 GET_BBLOCK (cfg, tbb, ip + 5);
9002                                 /* 
9003                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9004                                  * from Monitor.Enter like ArgumentNullException.
9005                                  */
9006                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9007                                         /* Mark this bblock as needing to be extended */
9008                                         tbb->extend_try_block = TRUE;
9009                                 }
9010                         }
9011
9012                         /* Conversion to a JIT intrinsic */
9013                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9014                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9015                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9016                                         emit_widen = FALSE;
9017                                 }
9018                                 goto call_end;
9019                         }
9020                         CHECK_CFG_ERROR;
9021                         
9022                         /* Inlining */
9023                         if ((cfg->opt & MONO_OPT_INLINE) &&
9024                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9025                             mono_method_check_inlining (cfg, cmethod)) {
9026                                 int costs;
9027                                 gboolean always = FALSE;
9028
9029                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9030                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9031                                         /* Prevent inlining of methods that call wrappers */
9032                                         INLINE_FAILURE ("wrapper call");
9033                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9034                                         always = TRUE;
9035                                 }
9036
9037                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9038                                 if (costs) {
9039                                         cfg->real_offset += 5;
9040
9041                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9042                                                 /* *sp is already set by inline_method */
9043                                                 sp++;
9044                                                 push_res = FALSE;
9045                                         }
9046
9047                                         inline_costs += costs;
9048
9049                                         goto call_end;
9050                                 }
9051                         }
9052
9053                         /* Tail recursion elimination */
9054                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9055                                 gboolean has_vtargs = FALSE;
9056                                 int i;
9057
9058                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9059                                 INLINE_FAILURE ("tail call");
9060
9061                                 /* keep it simple */
9062                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9063                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9064                                                 has_vtargs = TRUE;
9065                                 }
9066
9067                                 if (!has_vtargs) {
9068                                         if (need_seq_point) {
9069                                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9070                                                 need_seq_point = FALSE;
9071                                         }
9072                                         for (i = 0; i < n; ++i)
9073                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9074                                         MONO_INST_NEW (cfg, ins, OP_BR);
9075                                         MONO_ADD_INS (cfg->cbb, ins);
9076                                         tblock = start_bblock->out_bb [0];
9077                                         link_bblock (cfg, cfg->cbb, tblock);
9078                                         ins->inst_target_bb = tblock;
9079                                         start_new_bblock = 1;
9080
9081                                         /* skip the CEE_RET, too */
9082                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9083                                                 skip_ret = TRUE;
9084                                         push_res = FALSE;
9085                                         goto call_end;
9086                                 }
9087                         }
9088
9089                         inline_costs += 10 * num_calls++;
9090
9091                         /*
9092                          * Synchronized wrappers.
9093                          * Its hard to determine where to replace a method with its synchronized
9094                          * wrapper without causing an infinite recursion. The current solution is
9095                          * to add the synchronized wrapper in the trampolines, and to
9096                          * change the called method to a dummy wrapper, and resolve that wrapper
9097                          * to the real method in mono_jit_compile_method ().
9098                          */
9099                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9100                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9101                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9102                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9103                         }
9104
9105                         /*
9106                          * Making generic calls out of gsharedvt methods.
9107                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9108                          * patching gshared method addresses into a gsharedvt method.
9109                          */
9110                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) &&
9111                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9112                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9113                                 MonoRgctxInfoType info_type;
9114
9115                                 if (virtual_) {
9116                                         //if (mono_class_is_interface (cmethod->klass))
9117                                                 //GSHAREDVT_FAILURE (*ip);
9118                                         // disable for possible remoting calls
9119                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9120                                                 GSHAREDVT_FAILURE (*ip);
9121                                         if (fsig->generic_param_count) {
9122                                                 /* virtual generic call */
9123                                                 g_assert (!imt_arg);
9124                                                 /* Same as the virtual generic case above */
9125                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9126                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9127                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9128                                                 vtable_arg = NULL;
9129                                         } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) {
9130                                                 /* This can happen when we call a fully instantiated iface method */
9131                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9132                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9133                                                 vtable_arg = NULL;
9134                                         }
9135                                 }
9136
9137                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9138                                         keep_this_alive = sp [0];
9139
9140                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9141                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9142                                 else
9143                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9144                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9145
9146                                 if (cfg->llvm_only) {
9147                                         // FIXME: Avoid initializing vtable_arg
9148                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9149                                 } else {
9150                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9151                                 }
9152                                 goto call_end;
9153                         }
9154
9155                         /* Generic sharing */
9156
9157                         /*
9158                          * Use this if the callee is gsharedvt sharable too, since
9159                          * at runtime we might find an instantiation so the call cannot
9160                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9161                          */
9162                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9163                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9164                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9165                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9166                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9167                                 INLINE_FAILURE ("gshared");
9168
9169                                 g_assert (cfg->gshared && cmethod);
9170                                 g_assert (!addr);
9171
9172                                 /*
9173                                  * We are compiling a call to a
9174                                  * generic method from shared code,
9175                                  * which means that we have to look up
9176                                  * the method in the rgctx and do an
9177                                  * indirect call.
9178                                  */
9179                                 if (fsig->hasthis)
9180                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9181
9182                                 if (cfg->llvm_only) {
9183                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9184                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9185                                         else
9186                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9187                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9188                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9189                                 } else {
9190                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9191                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9192                                 }
9193                                 goto call_end;
9194                         }
9195
9196                         /* Direct calls to icalls */
9197                         if (direct_icall) {
9198                                 MonoMethod *wrapper;
9199                                 int costs;
9200
9201                                 /* Inline the wrapper */
9202                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9203
9204                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9205                                 g_assert (costs > 0);
9206                                 cfg->real_offset += 5;
9207
9208                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9209                                         /* *sp is already set by inline_method */
9210                                         sp++;
9211                                         push_res = FALSE;
9212                                 }
9213
9214                                 inline_costs += costs;
9215
9216                                 goto call_end;
9217                         }
9218                                         
9219                         /* Array methods */
9220                         if (array_rank) {
9221                                 MonoInst *addr;
9222
9223                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9224                                         MonoInst *val = sp [fsig->param_count];
9225
9226                                         if (val->type == STACK_OBJ) {
9227                                                 MonoInst *iargs [2];
9228
9229                                                 iargs [0] = sp [0];
9230                                                 iargs [1] = val;
9231                                                 
9232                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9233                                         }
9234                                         
9235                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9236                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9237                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
9238                                                 emit_write_barrier (cfg, addr, val);
9239                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9240                                                 GSHAREDVT_FAILURE (*ip);
9241                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9242                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9243
9244                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9245                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9246                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9247                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9248                                         CHECK_TYPELOAD (cmethod->klass);
9249                                         
9250                                         readonly = FALSE;
9251                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9252                                         ins = addr;
9253                                 } else {
9254                                         g_assert_not_reached ();
9255                                 }
9256
9257                                 emit_widen = FALSE;
9258                                 goto call_end;
9259                         }
9260
9261                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9262                         if (ins)
9263                                 goto call_end;
9264
9265                         /* Tail prefix / tail call optimization */
9266
9267                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9268                         /* FIXME: runtime generic context pointer for jumps? */
9269                         /* FIXME: handle this for generic sharing eventually */
9270                         if ((ins_flag & MONO_INST_TAILCALL) &&
9271                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9272                                 supported_tail_call = TRUE;
9273
9274                         if (supported_tail_call) {
9275                                 MonoCallInst *call;
9276
9277                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9278                                 INLINE_FAILURE ("tail call");
9279
9280                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9281
9282                                 if (cfg->backend->have_op_tail_call) {
9283                                         /* Handle tail calls similarly to normal calls */
9284                                         tail_call = TRUE;
9285                                 } else {
9286                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9287
9288                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9289                                         call->tail_call = TRUE;
9290                                         call->method = cmethod;
9291                                         call->signature = mono_method_signature (cmethod);
9292
9293                                         /*
9294                                          * We implement tail calls by storing the actual arguments into the 
9295                                          * argument variables, then emitting a CEE_JMP.
9296                                          */
9297                                         for (i = 0; i < n; ++i) {
9298                                                 /* Prevent argument from being register allocated */
9299                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9300                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9301                                         }
9302                                         ins = (MonoInst*)call;
9303                                         ins->inst_p0 = cmethod;
9304                                         ins->inst_p1 = arg_array [0];
9305                                         MONO_ADD_INS (cfg->cbb, ins);
9306                                         link_bblock (cfg, cfg->cbb, end_bblock);
9307                                         start_new_bblock = 1;
9308
9309                                         // FIXME: Eliminate unreachable epilogs
9310
9311                                         /*
9312                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9313                                          * only reachable from this call.
9314                                          */
9315                                         GET_BBLOCK (cfg, tblock, ip + 5);
9316                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9317                                                 skip_ret = TRUE;
9318                                         push_res = FALSE;
9319
9320                                         goto call_end;
9321                                 }
9322                         }
9323
9324                         /*
9325                          * Virtual calls in llvm-only mode.
9326                          */
9327                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9328                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9329                                 goto call_end;
9330                         }
9331
9332                         /* Common call */
9333                         if (!(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
9334                                 INLINE_FAILURE ("call");
9335                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9336                                                                                           imt_arg, vtable_arg);
9337
9338                         if (tail_call && !cfg->llvm_only) {
9339                                 link_bblock (cfg, cfg->cbb, end_bblock);
9340                                 start_new_bblock = 1;
9341
9342                                 // FIXME: Eliminate unreachable epilogs
9343
9344                                 /*
9345                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9346                                  * only reachable from this call.
9347                                  */
9348                                 GET_BBLOCK (cfg, tblock, ip + 5);
9349                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9350                                         skip_ret = TRUE;
9351                                 push_res = FALSE;
9352                         }
9353
9354                         call_end:
9355
9356                         /* End of call, INS should contain the result of the call, if any */
9357
9358                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9359                                 g_assert (ins);
9360                                 if (emit_widen)
9361                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9362                                 else
9363                                         *sp++ = ins;
9364                         }
9365
9366                         if (keep_this_alive) {
9367                                 MonoInst *dummy_use;
9368
9369                                 /* See mono_emit_method_call_full () */
9370                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9371                         }
9372
9373                         if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
9374                                 /*
9375                                  * Clang can convert these calls to tail calls which screw up the stack
9376                                  * walk. This happens even when the -fno-optimize-sibling-calls
9377                                  * option is passed to clang.
9378                                  * Work around this by emitting a dummy call.
9379                                  */
9380                                 mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
9381                         }
9382
9383                         CHECK_CFG_EXCEPTION;
9384
9385                         ip += 5;
9386                         if (skip_ret) {
9387                                 g_assert (*ip == CEE_RET);
9388                                 ip += 1;
9389                         }
9390                         ins_flag = 0;
9391                         constrained_class = NULL;
9392                         if (need_seq_point)
9393                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9394                         break;
9395                 }
9396                 case CEE_RET:
9397                         if (cfg->method != method) {
9398                                 /* return from inlined method */
9399                                 /* 
9400                                  * If in_count == 0, that means the ret is unreachable due to
9401                                  * being preceeded by a throw. In that case, inline_method () will
9402                                  * handle setting the return value 
9403                                  * (test case: test_0_inline_throw ()).
9404                                  */
9405                                 if (return_var && cfg->cbb->in_count) {
9406                                         MonoType *ret_type = mono_method_signature (method)->ret;
9407
9408                                         MonoInst *store;
9409                                         CHECK_STACK (1);
9410                                         --sp;
9411
9412                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9413                                                 UNVERIFIED;
9414
9415                                         //g_assert (returnvar != -1);
9416                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9417                                         cfg->ret_var_set = TRUE;
9418                                 } 
9419                         } else {
9420                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9421
9422                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9423                                         emit_pop_lmf (cfg);
9424
9425                                 if (cfg->ret) {
9426                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9427
9428                                         if (seq_points && !sym_seq_points) {
9429                                                 /* 
9430                                                  * Place a seq point here too even through the IL stack is not
9431                                                  * empty, so a step over on
9432                                                  * call <FOO>
9433                                                  * ret
9434                                                  * will work correctly.
9435                                                  */
9436                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9437                                                 MONO_ADD_INS (cfg->cbb, ins);
9438                                         }
9439
9440                                         g_assert (!return_var);
9441                                         CHECK_STACK (1);
9442                                         --sp;
9443
9444                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9445                                                 UNVERIFIED;
9446
9447                                         emit_setret (cfg, *sp);
9448                                 }
9449                         }
9450                         if (sp != stack_start)
9451                                 UNVERIFIED;
9452                         MONO_INST_NEW (cfg, ins, OP_BR);
9453                         ip++;
9454                         ins->inst_target_bb = end_bblock;
9455                         MONO_ADD_INS (cfg->cbb, ins);
9456                         link_bblock (cfg, cfg->cbb, end_bblock);
9457                         start_new_bblock = 1;
9458                         break;
9459                 case CEE_BR_S:
9460                         CHECK_OPSIZE (2);
9461                         MONO_INST_NEW (cfg, ins, OP_BR);
9462                         ip++;
9463                         target = ip + 1 + (signed char)(*ip);
9464                         ++ip;
9465                         GET_BBLOCK (cfg, tblock, target);
9466                         link_bblock (cfg, cfg->cbb, tblock);
9467                         ins->inst_target_bb = tblock;
9468                         if (sp != stack_start) {
9469                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9470                                 sp = stack_start;
9471                                 CHECK_UNVERIFIABLE (cfg);
9472                         }
9473                         MONO_ADD_INS (cfg->cbb, ins);
9474                         start_new_bblock = 1;
9475                         inline_costs += BRANCH_COST;
9476                         break;
9477                 case CEE_BEQ_S:
9478                 case CEE_BGE_S:
9479                 case CEE_BGT_S:
9480                 case CEE_BLE_S:
9481                 case CEE_BLT_S:
9482                 case CEE_BNE_UN_S:
9483                 case CEE_BGE_UN_S:
9484                 case CEE_BGT_UN_S:
9485                 case CEE_BLE_UN_S:
9486                 case CEE_BLT_UN_S:
9487                         CHECK_OPSIZE (2);
9488                         CHECK_STACK (2);
9489                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9490                         ip++;
9491                         target = ip + 1 + *(signed char*)ip;
9492                         ip++;
9493
9494                         ADD_BINCOND (NULL);
9495
9496                         sp = stack_start;
9497                         inline_costs += BRANCH_COST;
9498                         break;
9499                 case CEE_BR:
9500                         CHECK_OPSIZE (5);
9501                         MONO_INST_NEW (cfg, ins, OP_BR);
9502                         ip++;
9503
9504                         target = ip + 4 + (gint32)read32(ip);
9505                         ip += 4;
9506                         GET_BBLOCK (cfg, tblock, target);
9507                         link_bblock (cfg, cfg->cbb, tblock);
9508                         ins->inst_target_bb = tblock;
9509                         if (sp != stack_start) {
9510                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9511                                 sp = stack_start;
9512                                 CHECK_UNVERIFIABLE (cfg);
9513                         }
9514
9515                         MONO_ADD_INS (cfg->cbb, ins);
9516
9517                         start_new_bblock = 1;
9518                         inline_costs += BRANCH_COST;
9519                         break;
9520                 case CEE_BRFALSE_S:
9521                 case CEE_BRTRUE_S:
9522                 case CEE_BRFALSE:
9523                 case CEE_BRTRUE: {
9524                         MonoInst *cmp;
9525                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9526                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9527                         guint32 opsize = is_short ? 1 : 4;
9528
9529                         CHECK_OPSIZE (opsize);
9530                         CHECK_STACK (1);
9531                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9532                                 UNVERIFIED;
9533                         ip ++;
9534                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9535                         ip += opsize;
9536
9537                         sp--;
9538
9539                         GET_BBLOCK (cfg, tblock, target);
9540                         link_bblock (cfg, cfg->cbb, tblock);
9541                         GET_BBLOCK (cfg, tblock, ip);
9542                         link_bblock (cfg, cfg->cbb, tblock);
9543
9544                         if (sp != stack_start) {
9545                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9546                                 CHECK_UNVERIFIABLE (cfg);
9547                         }
9548
9549                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9550                         cmp->sreg1 = sp [0]->dreg;
9551                         type_from_op (cfg, cmp, sp [0], NULL);
9552                         CHECK_TYPE (cmp);
9553
9554 #if SIZEOF_REGISTER == 4
9555                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9556                                 /* Convert it to OP_LCOMPARE */
9557                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9558                                 ins->type = STACK_I8;
9559                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9560                                 ins->inst_l = 0;
9561                                 MONO_ADD_INS (cfg->cbb, ins);
9562                                 cmp->opcode = OP_LCOMPARE;
9563                                 cmp->sreg2 = ins->dreg;
9564                         }
9565 #endif
9566                         MONO_ADD_INS (cfg->cbb, cmp);
9567
9568                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9569                         type_from_op (cfg, ins, sp [0], NULL);
9570                         MONO_ADD_INS (cfg->cbb, ins);
9571                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9572                         GET_BBLOCK (cfg, tblock, target);
9573                         ins->inst_true_bb = tblock;
9574                         GET_BBLOCK (cfg, tblock, ip);
9575                         ins->inst_false_bb = tblock;
9576                         start_new_bblock = 2;
9577
9578                         sp = stack_start;
9579                         inline_costs += BRANCH_COST;
9580                         break;
9581                 }
9582                 case CEE_BEQ:
9583                 case CEE_BGE:
9584                 case CEE_BGT:
9585                 case CEE_BLE:
9586                 case CEE_BLT:
9587                 case CEE_BNE_UN:
9588                 case CEE_BGE_UN:
9589                 case CEE_BGT_UN:
9590                 case CEE_BLE_UN:
9591                 case CEE_BLT_UN:
9592                         CHECK_OPSIZE (5);
9593                         CHECK_STACK (2);
9594                         MONO_INST_NEW (cfg, ins, *ip);
9595                         ip++;
9596                         target = ip + 4 + (gint32)read32(ip);
9597                         ip += 4;
9598
9599                         ADD_BINCOND (NULL);
9600
9601                         sp = stack_start;
9602                         inline_costs += BRANCH_COST;
9603                         break;
9604                 case CEE_SWITCH: {
9605                         MonoInst *src1;
9606                         MonoBasicBlock **targets;
9607                         MonoBasicBlock *default_bblock;
9608                         MonoJumpInfoBBTable *table;
9609                         int offset_reg = alloc_preg (cfg);
9610                         int target_reg = alloc_preg (cfg);
9611                         int table_reg = alloc_preg (cfg);
9612                         int sum_reg = alloc_preg (cfg);
9613                         gboolean use_op_switch;
9614
9615                         CHECK_OPSIZE (5);
9616                         CHECK_STACK (1);
9617                         n = read32 (ip + 1);
9618                         --sp;
9619                         src1 = sp [0];
9620                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9621                                 UNVERIFIED;
9622
9623                         ip += 5;
9624                         CHECK_OPSIZE (n * sizeof (guint32));
9625                         target = ip + n * sizeof (guint32);
9626
9627                         GET_BBLOCK (cfg, default_bblock, target);
9628                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9629
9630                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9631                         for (i = 0; i < n; ++i) {
9632                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9633                                 targets [i] = tblock;
9634                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9635                                 ip += 4;
9636                         }
9637
9638                         if (sp != stack_start) {
9639                                 /* 
9640                                  * Link the current bb with the targets as well, so handle_stack_args
9641                                  * will set their in_stack correctly.
9642                                  */
9643                                 link_bblock (cfg, cfg->cbb, default_bblock);
9644                                 for (i = 0; i < n; ++i)
9645                                         link_bblock (cfg, cfg->cbb, targets [i]);
9646
9647                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9648                                 sp = stack_start;
9649                                 CHECK_UNVERIFIABLE (cfg);
9650
9651                                 /* Undo the links */
9652                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9653                                 for (i = 0; i < n; ++i)
9654                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9655                         }
9656
9657                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9658                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9659
9660                         for (i = 0; i < n; ++i)
9661                                 link_bblock (cfg, cfg->cbb, targets [i]);
9662
9663                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9664                         table->table = targets;
9665                         table->table_size = n;
9666
9667                         use_op_switch = FALSE;
9668 #ifdef TARGET_ARM
9669                         /* ARM implements SWITCH statements differently */
9670                         /* FIXME: Make it use the generic implementation */
9671                         if (!cfg->compile_aot)
9672                                 use_op_switch = TRUE;
9673 #endif
9674
9675                         if (COMPILE_LLVM (cfg))
9676                                 use_op_switch = TRUE;
9677
9678                         cfg->cbb->has_jump_table = 1;
9679
9680                         if (use_op_switch) {
9681                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9682                                 ins->sreg1 = src1->dreg;
9683                                 ins->inst_p0 = table;
9684                                 ins->inst_many_bb = targets;
9685                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
9686                                 MONO_ADD_INS (cfg->cbb, ins);
9687                         } else {
9688                                 if (sizeof (gpointer) == 8)
9689                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9690                                 else
9691                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9692
9693 #if SIZEOF_REGISTER == 8
9694                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9695                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9696 #endif
9697
9698                                 if (cfg->compile_aot) {
9699                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9700                                 } else {
9701                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9702                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9703                                         ins->inst_p0 = table;
9704                                         ins->dreg = table_reg;
9705                                         MONO_ADD_INS (cfg->cbb, ins);
9706                                 }
9707
9708                                 /* FIXME: Use load_memindex */
9709                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9710                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9711                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9712                         }
9713                         start_new_bblock = 1;
9714                         inline_costs += (BRANCH_COST * 2);
9715                         break;
9716                 }
9717                 case CEE_LDIND_I1:
9718                 case CEE_LDIND_U1:
9719                 case CEE_LDIND_I2:
9720                 case CEE_LDIND_U2:
9721                 case CEE_LDIND_I4:
9722                 case CEE_LDIND_U4:
9723                 case CEE_LDIND_I8:
9724                 case CEE_LDIND_I:
9725                 case CEE_LDIND_R4:
9726                 case CEE_LDIND_R8:
9727                 case CEE_LDIND_REF:
9728                         CHECK_STACK (1);
9729                         --sp;
9730
9731                         switch (*ip) {
9732                         case CEE_LDIND_R4:
9733                         case CEE_LDIND_R8:
9734                                 dreg = alloc_freg (cfg);
9735                                 break;
9736                         case CEE_LDIND_I8:
9737                                 dreg = alloc_lreg (cfg);
9738                                 break;
9739                         case CEE_LDIND_REF:
9740                                 dreg = alloc_ireg_ref (cfg);
9741                                 break;
9742                         default:
9743                                 dreg = alloc_preg (cfg);
9744                         }
9745
9746                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9747                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9748                         if (*ip == CEE_LDIND_R4)
9749                                 ins->type = cfg->r4_stack_type;
9750                         ins->flags |= ins_flag;
9751                         MONO_ADD_INS (cfg->cbb, ins);
9752                         *sp++ = ins;
9753                         if (ins_flag & MONO_INST_VOLATILE) {
9754                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9755                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9756                         }
9757                         ins_flag = 0;
9758                         ++ip;
9759                         break;
9760                 case CEE_STIND_REF:
9761                 case CEE_STIND_I1:
9762                 case CEE_STIND_I2:
9763                 case CEE_STIND_I4:
9764                 case CEE_STIND_I8:
9765                 case CEE_STIND_R4:
9766                 case CEE_STIND_R8:
9767                 case CEE_STIND_I:
9768                         CHECK_STACK (2);
9769                         sp -= 2;
9770
9771                         if (ins_flag & MONO_INST_VOLATILE) {
9772                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9773                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9774                         }
9775
9776                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9777                         ins->flags |= ins_flag;
9778                         ins_flag = 0;
9779
9780                         MONO_ADD_INS (cfg->cbb, ins);
9781
9782                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
9783                                 emit_write_barrier (cfg, sp [0], sp [1]);
9784
9785                         inline_costs += 1;
9786                         ++ip;
9787                         break;
9788
9789                 case CEE_MUL:
9790                         CHECK_STACK (2);
9791
9792                         MONO_INST_NEW (cfg, ins, (*ip));
9793                         sp -= 2;
9794                         ins->sreg1 = sp [0]->dreg;
9795                         ins->sreg2 = sp [1]->dreg;
9796                         type_from_op (cfg, ins, sp [0], sp [1]);
9797                         CHECK_TYPE (ins);
9798                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9799
9800                         /* Use the immediate opcodes if possible */
9801                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9802                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9803                                 if (imm_opcode != -1) {
9804                                         ins->opcode = imm_opcode;
9805                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9806                                         ins->sreg2 = -1;
9807
9808                                         NULLIFY_INS (sp [1]);
9809                                 }
9810                         }
9811
9812                         MONO_ADD_INS ((cfg)->cbb, (ins));
9813
9814                         *sp++ = mono_decompose_opcode (cfg, ins);
9815                         ip++;
9816                         break;
9817                 case CEE_ADD:
9818                 case CEE_SUB:
9819                 case CEE_DIV:
9820                 case CEE_DIV_UN:
9821                 case CEE_REM:
9822                 case CEE_REM_UN:
9823                 case CEE_AND:
9824                 case CEE_OR:
9825                 case CEE_XOR:
9826                 case CEE_SHL:
9827                 case CEE_SHR:
9828                 case CEE_SHR_UN:
9829                         CHECK_STACK (2);
9830
9831                         MONO_INST_NEW (cfg, ins, (*ip));
9832                         sp -= 2;
9833                         ins->sreg1 = sp [0]->dreg;
9834                         ins->sreg2 = sp [1]->dreg;
9835                         type_from_op (cfg, ins, sp [0], sp [1]);
9836                         CHECK_TYPE (ins);
9837                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9838                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9839
9840                         /* FIXME: Pass opcode to is_inst_imm */
9841
9842                         /* Use the immediate opcodes if possible */
9843                         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)) {
9844                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9845                                 if (imm_opcode != -1) {
9846                                         ins->opcode = imm_opcode;
9847                                         if (sp [1]->opcode == OP_I8CONST) {
9848 #if SIZEOF_REGISTER == 8
9849                                                 ins->inst_imm = sp [1]->inst_l;
9850 #else
9851                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9852                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9853 #endif
9854                                         }
9855                                         else
9856                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9857                                         ins->sreg2 = -1;
9858
9859                                         /* Might be followed by an instruction added by add_widen_op */
9860                                         if (sp [1]->next == NULL)
9861                                                 NULLIFY_INS (sp [1]);
9862                                 }
9863                         }
9864                         MONO_ADD_INS ((cfg)->cbb, (ins));
9865
9866                         *sp++ = mono_decompose_opcode (cfg, ins);
9867                         ip++;
9868                         break;
9869                 case CEE_NEG:
9870                 case CEE_NOT:
9871                 case CEE_CONV_I1:
9872                 case CEE_CONV_I2:
9873                 case CEE_CONV_I4:
9874                 case CEE_CONV_R4:
9875                 case CEE_CONV_R8:
9876                 case CEE_CONV_U4:
9877                 case CEE_CONV_I8:
9878                 case CEE_CONV_U8:
9879                 case CEE_CONV_OVF_I8:
9880                 case CEE_CONV_OVF_U8:
9881                 case CEE_CONV_R_UN:
9882                         CHECK_STACK (1);
9883
9884                         /* Special case this earlier so we have long constants in the IR */
9885                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9886                                 int data = sp [-1]->inst_c0;
9887                                 sp [-1]->opcode = OP_I8CONST;
9888                                 sp [-1]->type = STACK_I8;
9889 #if SIZEOF_REGISTER == 8
9890                                 if ((*ip) == CEE_CONV_U8)
9891                                         sp [-1]->inst_c0 = (guint32)data;
9892                                 else
9893                                         sp [-1]->inst_c0 = data;
9894 #else
9895                                 sp [-1]->inst_ls_word = data;
9896                                 if ((*ip) == CEE_CONV_U8)
9897                                         sp [-1]->inst_ms_word = 0;
9898                                 else
9899                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9900 #endif
9901                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9902                         }
9903                         else {
9904                                 ADD_UNOP (*ip);
9905                         }
9906                         ip++;
9907                         break;
9908                 case CEE_CONV_OVF_I4:
9909                 case CEE_CONV_OVF_I1:
9910                 case CEE_CONV_OVF_I2:
9911                 case CEE_CONV_OVF_I:
9912                 case CEE_CONV_OVF_U:
9913                         CHECK_STACK (1);
9914
9915                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9916                                 ADD_UNOP (CEE_CONV_OVF_I8);
9917                                 ADD_UNOP (*ip);
9918                         } else {
9919                                 ADD_UNOP (*ip);
9920                         }
9921                         ip++;
9922                         break;
9923                 case CEE_CONV_OVF_U1:
9924                 case CEE_CONV_OVF_U2:
9925                 case CEE_CONV_OVF_U4:
9926                         CHECK_STACK (1);
9927
9928                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9929                                 ADD_UNOP (CEE_CONV_OVF_U8);
9930                                 ADD_UNOP (*ip);
9931                         } else {
9932                                 ADD_UNOP (*ip);
9933                         }
9934                         ip++;
9935                         break;
9936                 case CEE_CONV_OVF_I1_UN:
9937                 case CEE_CONV_OVF_I2_UN:
9938                 case CEE_CONV_OVF_I4_UN:
9939                 case CEE_CONV_OVF_I8_UN:
9940                 case CEE_CONV_OVF_U1_UN:
9941                 case CEE_CONV_OVF_U2_UN:
9942                 case CEE_CONV_OVF_U4_UN:
9943                 case CEE_CONV_OVF_U8_UN:
9944                 case CEE_CONV_OVF_I_UN:
9945                 case CEE_CONV_OVF_U_UN:
9946                 case CEE_CONV_U2:
9947                 case CEE_CONV_U1:
9948                 case CEE_CONV_I:
9949                 case CEE_CONV_U:
9950                         CHECK_STACK (1);
9951                         ADD_UNOP (*ip);
9952                         CHECK_CFG_EXCEPTION;
9953                         ip++;
9954                         break;
9955                 case CEE_ADD_OVF:
9956                 case CEE_ADD_OVF_UN:
9957                 case CEE_MUL_OVF:
9958                 case CEE_MUL_OVF_UN:
9959                 case CEE_SUB_OVF:
9960                 case CEE_SUB_OVF_UN:
9961                         CHECK_STACK (2);
9962                         ADD_BINOP (*ip);
9963                         ip++;
9964                         break;
9965                 case CEE_CPOBJ:
9966                         GSHAREDVT_FAILURE (*ip);
9967                         CHECK_OPSIZE (5);
9968                         CHECK_STACK (2);
9969                         token = read32 (ip + 1);
9970                         klass = mini_get_class (method, token, generic_context);
9971                         CHECK_TYPELOAD (klass);
9972                         sp -= 2;
9973                         if (generic_class_is_reference_type (cfg, klass)) {
9974                                 MonoInst *store, *load;
9975                                 int dreg = alloc_ireg_ref (cfg);
9976
9977                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9978                                 load->flags |= ins_flag;
9979                                 MONO_ADD_INS (cfg->cbb, load);
9980
9981                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9982                                 store->flags |= ins_flag;
9983                                 MONO_ADD_INS (cfg->cbb, store);
9984
9985                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9986                                         emit_write_barrier (cfg, sp [0], sp [1]);
9987                         } else {
9988                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9989                         }
9990                         ins_flag = 0;
9991                         ip += 5;
9992                         break;
9993                 case CEE_LDOBJ: {
9994                         int loc_index = -1;
9995                         int stloc_len = 0;
9996
9997                         CHECK_OPSIZE (5);
9998                         CHECK_STACK (1);
9999                         --sp;
10000                         token = read32 (ip + 1);
10001                         klass = mini_get_class (method, token, generic_context);
10002                         CHECK_TYPELOAD (klass);
10003
10004                         /* Optimize the common ldobj+stloc combination */
10005                         switch (ip [5]) {
10006                         case CEE_STLOC_S:
10007                                 loc_index = ip [6];
10008                                 stloc_len = 2;
10009                                 break;
10010                         case CEE_STLOC_0:
10011                         case CEE_STLOC_1:
10012                         case CEE_STLOC_2:
10013                         case CEE_STLOC_3:
10014                                 loc_index = ip [5] - CEE_STLOC_0;
10015                                 stloc_len = 1;
10016                                 break;
10017                         default:
10018                                 break;
10019                         }
10020
10021                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10022                                 CHECK_LOCAL (loc_index);
10023
10024                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10025                                 ins->dreg = cfg->locals [loc_index]->dreg;
10026                                 ins->flags |= ins_flag;
10027                                 ip += 5;
10028                                 ip += stloc_len;
10029                                 if (ins_flag & MONO_INST_VOLATILE) {
10030                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10031                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10032                                 }
10033                                 ins_flag = 0;
10034                                 break;
10035                         }
10036
10037                         /* Optimize the ldobj+stobj combination */
10038                         /* The reference case ends up being a load+store anyway */
10039                         /* Skip this if the operation is volatile. */
10040                         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)) {
10041                                 CHECK_STACK (1);
10042
10043                                 sp --;
10044
10045                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10046
10047                                 ip += 5 + 5;
10048                                 ins_flag = 0;
10049                                 break;
10050                         }
10051
10052                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10053                         ins->flags |= ins_flag;
10054                         *sp++ = ins;
10055
10056                         if (ins_flag & MONO_INST_VOLATILE) {
10057                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10058                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10059                         }
10060
10061                         ip += 5;
10062                         ins_flag = 0;
10063                         inline_costs += 1;
10064                         break;
10065                 }
10066                 case CEE_LDSTR:
10067                         CHECK_STACK_OVF (1);
10068                         CHECK_OPSIZE (5);
10069                         n = read32 (ip + 1);
10070
10071                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10072                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10073                                 ins->type = STACK_OBJ;
10074                                 *sp = ins;
10075                         }
10076                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10077                                 MonoInst *iargs [1];
10078                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10079
10080                                 if (cfg->compile_aot)
10081                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10082                                 else
10083                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10084                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10085                         } else {
10086                                 if (cfg->opt & MONO_OPT_SHARED) {
10087                                         MonoInst *iargs [3];
10088
10089                                         if (cfg->compile_aot) {
10090                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10091                                         }
10092                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10093                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10094                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10095                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10096                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10097                                         CHECK_CFG_ERROR;
10098                                 } else {
10099                                         if (cfg->cbb->out_of_line) {
10100                                                 MonoInst *iargs [2];
10101
10102                                                 if (image == mono_defaults.corlib) {
10103                                                         /* 
10104                                                          * Avoid relocations in AOT and save some space by using a 
10105                                                          * version of helper_ldstr specialized to mscorlib.
10106                                                          */
10107                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10108                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10109                                                 } else {
10110                                                         /* Avoid creating the string object */
10111                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10112                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10113                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10114                                                 }
10115                                         } 
10116                                         else
10117                                         if (cfg->compile_aot) {
10118                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10119                                                 *sp = ins;
10120                                                 MONO_ADD_INS (cfg->cbb, ins);
10121                                         } 
10122                                         else {
10123                                                 NEW_PCONST (cfg, ins, NULL);
10124                                                 ins->type = STACK_OBJ;
10125                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10126                                                 CHECK_CFG_ERROR;
10127                                                 
10128                                                 if (!ins->inst_p0)
10129                                                         OUT_OF_MEMORY_FAILURE;
10130
10131                                                 *sp = ins;
10132                                                 MONO_ADD_INS (cfg->cbb, ins);
10133                                         }
10134                                 }
10135                         }
10136
10137                         sp++;
10138                         ip += 5;
10139                         break;
10140                 case CEE_NEWOBJ: {
10141                         MonoInst *iargs [2];
10142                         MonoMethodSignature *fsig;
10143                         MonoInst this_ins;
10144                         MonoInst *alloc;
10145                         MonoInst *vtable_arg = NULL;
10146
10147                         CHECK_OPSIZE (5);
10148                         token = read32 (ip + 1);
10149                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10150                         CHECK_CFG_ERROR;
10151
10152                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10153                         CHECK_CFG_ERROR;
10154
10155                         mono_save_token_info (cfg, image, token, cmethod);
10156
10157                         if (!mono_class_init (cmethod->klass))
10158                                 TYPE_LOAD_ERROR (cmethod->klass);
10159
10160                         context_used = mini_method_check_context_used (cfg, cmethod);
10161
10162                         if (mono_security_core_clr_enabled ())
10163                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10164
10165                         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)) {
10166                                 emit_class_init (cfg, cmethod->klass);
10167                                 CHECK_TYPELOAD (cmethod->klass);
10168                         }
10169
10170                         /*
10171                         if (cfg->gsharedvt) {
10172                                 if (mini_is_gsharedvt_variable_signature (sig))
10173                                         GSHAREDVT_FAILURE (*ip);
10174                         }
10175                         */
10176
10177                         n = fsig->param_count;
10178                         CHECK_STACK (n);
10179
10180                         /* 
10181                          * Generate smaller code for the common newobj <exception> instruction in
10182                          * argument checking code.
10183                          */
10184                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10185                                 is_exception_class (cmethod->klass) && n <= 2 &&
10186                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10187                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10188                                 MonoInst *iargs [3];
10189
10190                                 sp -= n;
10191
10192                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10193                                 switch (n) {
10194                                 case 0:
10195                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10196                                         break;
10197                                 case 1:
10198                                         iargs [1] = sp [0];
10199                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10200                                         break;
10201                                 case 2:
10202                                         iargs [1] = sp [0];
10203                                         iargs [2] = sp [1];
10204                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10205                                         break;
10206                                 default:
10207                                         g_assert_not_reached ();
10208                                 }
10209
10210                                 ip += 5;
10211                                 inline_costs += 5;
10212                                 break;
10213                         }
10214
10215                         /* move the args to allow room for 'this' in the first position */
10216                         while (n--) {
10217                                 --sp;
10218                                 sp [1] = sp [0];
10219                         }
10220
10221                         /* check_call_signature () requires sp[0] to be set */
10222                         this_ins.type = STACK_OBJ;
10223                         sp [0] = &this_ins;
10224                         if (check_call_signature (cfg, fsig, sp))
10225                                 UNVERIFIED;
10226
10227                         iargs [0] = NULL;
10228
10229                         if (mini_class_is_system_array (cmethod->klass)) {
10230                                 *sp = emit_get_rgctx_method (cfg, context_used,
10231                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10232
10233                                 /* Avoid varargs in the common case */
10234                                 if (fsig->param_count == 1)
10235                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10236                                 else if (fsig->param_count == 2)
10237                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10238                                 else if (fsig->param_count == 3)
10239                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10240                                 else if (fsig->param_count == 4)
10241                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10242                                 else
10243                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10244                         } else if (cmethod->string_ctor) {
10245                                 g_assert (!context_used);
10246                                 g_assert (!vtable_arg);
10247                                 /* we simply pass a null pointer */
10248                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10249                                 /* now call the string ctor */
10250                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10251                         } else {
10252                                 if (cmethod->klass->valuetype) {
10253                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10254                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10255                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10256
10257                                         alloc = NULL;
10258
10259                                         /* 
10260                                          * The code generated by mini_emit_virtual_call () expects
10261                                          * iargs [0] to be a boxed instance, but luckily the vcall
10262                                          * will be transformed into a normal call there.
10263                                          */
10264                                 } else if (context_used) {
10265                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10266                                         *sp = alloc;
10267                                 } else {
10268                                         MonoVTable *vtable = NULL;
10269
10270                                         if (!cfg->compile_aot)
10271                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10272                                         CHECK_TYPELOAD (cmethod->klass);
10273
10274                                         /*
10275                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10276                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10277                                          * As a workaround, we call class cctors before allocating objects.
10278                                          */
10279                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10280                                                 emit_class_init (cfg, cmethod->klass);
10281                                                 if (cfg->verbose_level > 2)
10282                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10283                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10284                                         }
10285
10286                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10287                                         *sp = alloc;
10288                                 }
10289                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10290
10291                                 if (alloc)
10292                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10293
10294                                 /* Now call the actual ctor */
10295                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10296                                 CHECK_CFG_EXCEPTION;
10297                         }
10298
10299                         if (alloc == NULL) {
10300                                 /* Valuetype */
10301                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10302                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10303                                 *sp++= ins;
10304                         } else {
10305                                 *sp++ = alloc;
10306                         }
10307                         
10308                         ip += 5;
10309                         inline_costs += 5;
10310                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10311                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10312                         break;
10313                 }
10314                 case CEE_CASTCLASS:
10315                 case CEE_ISINST: {
10316                         CHECK_STACK (1);
10317                         --sp;
10318                         CHECK_OPSIZE (5);
10319                         token = read32 (ip + 1);
10320                         klass = mini_get_class (method, token, generic_context);
10321                         CHECK_TYPELOAD (klass);
10322                         if (sp [0]->type != STACK_OBJ)
10323                                 UNVERIFIED;
10324
10325                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
10326                         ins->dreg = alloc_preg (cfg);
10327                         ins->sreg1 = (*sp)->dreg;
10328                         ins->klass = klass;
10329                         ins->type = STACK_OBJ;
10330                         MONO_ADD_INS (cfg->cbb, ins);
10331
10332                         CHECK_CFG_EXCEPTION;
10333                         *sp++ = ins;
10334                         ip += 5;
10335
10336                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10337                         break;
10338                 }
10339                 case CEE_UNBOX_ANY: {
10340                         MonoInst *res, *addr;
10341
10342                         CHECK_STACK (1);
10343                         --sp;
10344                         CHECK_OPSIZE (5);
10345                         token = read32 (ip + 1);
10346                         klass = mini_get_class (method, token, generic_context);
10347                         CHECK_TYPELOAD (klass);
10348
10349                         mono_save_token_info (cfg, image, token, klass);
10350
10351                         context_used = mini_class_check_context_used (cfg, klass);
10352
10353                         if (mini_is_gsharedvt_klass (klass)) {
10354                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10355                                 inline_costs += 2;
10356                         } else if (generic_class_is_reference_type (cfg, klass)) {
10357                                 if (MONO_INS_IS_PCONST_NULL (*sp)) {
10358                                         EMIT_NEW_PCONST (cfg, res, NULL);
10359                                         res->type = STACK_OBJ;
10360                                 } else {
10361                                         MONO_INST_NEW (cfg, res, OP_CASTCLASS);
10362                                         res->dreg = alloc_preg (cfg);
10363                                         res->sreg1 = (*sp)->dreg;
10364                                         res->klass = klass;
10365                                         res->type = STACK_OBJ;
10366                                         MONO_ADD_INS (cfg->cbb, res);
10367                                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10368                                 }
10369                         } else if (mono_class_is_nullable (klass)) {
10370                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10371                         } else {
10372                                 addr = handle_unbox (cfg, klass, sp, context_used);
10373                                 /* LDOBJ */
10374                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10375                                 res = ins;
10376                                 inline_costs += 2;
10377                         }
10378
10379                         *sp ++ = res;
10380                         ip += 5;
10381                         break;
10382                 }
10383                 case CEE_BOX: {
10384                         MonoInst *val;
10385                         MonoClass *enum_class;
10386                         MonoMethod *has_flag;
10387
10388                         CHECK_STACK (1);
10389                         --sp;
10390                         val = *sp;
10391                         CHECK_OPSIZE (5);
10392                         token = read32 (ip + 1);
10393                         klass = mini_get_class (method, token, generic_context);
10394                         CHECK_TYPELOAD (klass);
10395
10396                         mono_save_token_info (cfg, image, token, klass);
10397
10398                         context_used = mini_class_check_context_used (cfg, klass);
10399
10400                         if (generic_class_is_reference_type (cfg, klass)) {
10401                                 *sp++ = val;
10402                                 ip += 5;
10403                                 break;
10404                         }
10405
10406                         if (klass == mono_defaults.void_class)
10407                                 UNVERIFIED;
10408                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10409                                 UNVERIFIED;
10410                         /* frequent check in generic code: box (struct), brtrue */
10411
10412                         /*
10413                          * Look for:
10414                          *
10415                          *   <push int/long ptr>
10416                          *   <push int/long>
10417                          *   box MyFlags
10418                          *   constrained. MyFlags
10419                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10420                          *
10421                          * If we find this sequence and the operand types on box and constrained
10422                          * are equal, we can emit a specialized instruction sequence instead of
10423                          * the very slow HasFlag () call.
10424                          */
10425                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10426                             /* Cheap checks first. */
10427                             ip + 5 + 6 + 5 < end &&
10428                             ip [5] == CEE_PREFIX1 &&
10429                             ip [6] == CEE_CONSTRAINED_ &&
10430                             ip [11] == CEE_CALLVIRT &&
10431                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10432                             mono_class_is_enum (klass) &&
10433                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10434                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10435                             has_flag->klass == mono_defaults.enum_class &&
10436                             !strcmp (has_flag->name, "HasFlag") &&
10437                             has_flag->signature->hasthis &&
10438                             has_flag->signature->param_count == 1) {
10439                                 CHECK_TYPELOAD (enum_class);
10440
10441                                 if (enum_class == klass) {
10442                                         MonoInst *enum_this, *enum_flag;
10443
10444                                         ip += 5 + 6 + 5;
10445                                         --sp;
10446
10447                                         enum_this = sp [0];
10448                                         enum_flag = sp [1];
10449
10450                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10451                                         break;
10452                                 }
10453                         }
10454
10455                         // FIXME: LLVM can't handle the inconsistent bb linking
10456                         if (!mono_class_is_nullable (klass) &&
10457                                 !mini_is_gsharedvt_klass (klass) &&
10458                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10459                                 (ip [5] == CEE_BRTRUE || 
10460                                  ip [5] == CEE_BRTRUE_S ||
10461                                  ip [5] == CEE_BRFALSE ||
10462                                  ip [5] == CEE_BRFALSE_S)) {
10463                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10464                                 int dreg;
10465                                 MonoBasicBlock *true_bb, *false_bb;
10466
10467                                 ip += 5;
10468
10469                                 if (cfg->verbose_level > 3) {
10470                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10471                                         printf ("<box+brtrue opt>\n");
10472                                 }
10473
10474                                 switch (*ip) {
10475                                 case CEE_BRTRUE_S:
10476                                 case CEE_BRFALSE_S:
10477                                         CHECK_OPSIZE (2);
10478                                         ip++;
10479                                         target = ip + 1 + (signed char)(*ip);
10480                                         ip++;
10481                                         break;
10482                                 case CEE_BRTRUE:
10483                                 case CEE_BRFALSE:
10484                                         CHECK_OPSIZE (5);
10485                                         ip++;
10486                                         target = ip + 4 + (gint)(read32 (ip));
10487                                         ip += 4;
10488                                         break;
10489                                 default:
10490                                         g_assert_not_reached ();
10491                                 }
10492
10493                                 /* 
10494                                  * We need to link both bblocks, since it is needed for handling stack
10495                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10496                                  * Branching to only one of them would lead to inconsistencies, so
10497                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10498                                  */
10499                                 GET_BBLOCK (cfg, true_bb, target);
10500                                 GET_BBLOCK (cfg, false_bb, ip);
10501
10502                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10503                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10504
10505                                 if (sp != stack_start) {
10506                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10507                                         sp = stack_start;
10508                                         CHECK_UNVERIFIABLE (cfg);
10509                                 }
10510
10511                                 if (COMPILE_LLVM (cfg)) {
10512                                         dreg = alloc_ireg (cfg);
10513                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10514                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10515
10516                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10517                                 } else {
10518                                         /* The JIT can't eliminate the iconst+compare */
10519                                         MONO_INST_NEW (cfg, ins, OP_BR);
10520                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10521                                         MONO_ADD_INS (cfg->cbb, ins);
10522                                 }
10523
10524                                 start_new_bblock = 1;
10525                                 break;
10526                         }
10527
10528                         *sp++ = handle_box (cfg, val, klass, context_used);
10529
10530                         CHECK_CFG_EXCEPTION;
10531                         ip += 5;
10532                         inline_costs += 1;
10533                         break;
10534                 }
10535                 case CEE_UNBOX: {
10536                         CHECK_STACK (1);
10537                         --sp;
10538                         CHECK_OPSIZE (5);
10539                         token = read32 (ip + 1);
10540                         klass = mini_get_class (method, token, generic_context);
10541                         CHECK_TYPELOAD (klass);
10542
10543                         mono_save_token_info (cfg, image, token, klass);
10544
10545                         context_used = mini_class_check_context_used (cfg, klass);
10546
10547                         if (mono_class_is_nullable (klass)) {
10548                                 MonoInst *val;
10549
10550                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10551                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10552
10553                                 *sp++= ins;
10554                         } else {
10555                                 ins = handle_unbox (cfg, klass, sp, context_used);
10556                                 *sp++ = ins;
10557                         }
10558                         ip += 5;
10559                         inline_costs += 2;
10560                         break;
10561                 }
10562                 case CEE_LDFLD:
10563                 case CEE_LDFLDA:
10564                 case CEE_STFLD:
10565                 case CEE_LDSFLD:
10566                 case CEE_LDSFLDA:
10567                 case CEE_STSFLD: {
10568                         MonoClassField *field;
10569 #ifndef DISABLE_REMOTING
10570                         int costs;
10571 #endif
10572                         guint foffset;
10573                         gboolean is_instance;
10574                         int op;
10575                         gpointer addr = NULL;
10576                         gboolean is_special_static;
10577                         MonoType *ftype;
10578                         MonoInst *store_val = NULL;
10579                         MonoInst *thread_ins;
10580
10581                         op = *ip;
10582                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10583                         if (is_instance) {
10584                                 if (op == CEE_STFLD) {
10585                                         CHECK_STACK (2);
10586                                         sp -= 2;
10587                                         store_val = sp [1];
10588                                 } else {
10589                                         CHECK_STACK (1);
10590                                         --sp;
10591                                 }
10592                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10593                                         UNVERIFIED;
10594                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10595                                         UNVERIFIED;
10596                         } else {
10597                                 if (op == CEE_STSFLD) {
10598                                         CHECK_STACK (1);
10599                                         sp--;
10600                                         store_val = sp [0];
10601                                 }
10602                         }
10603
10604                         CHECK_OPSIZE (5);
10605                         token = read32 (ip + 1);
10606                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10607                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
10608                                 klass = field->parent;
10609                         }
10610                         else {
10611                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10612                                 CHECK_CFG_ERROR;
10613                         }
10614                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10615                                 FIELD_ACCESS_FAILURE (method, field);
10616                         mono_class_init (klass);
10617
10618                         /* if the class is Critical then transparent code cannot access it's fields */
10619                         if (!is_instance && mono_security_core_clr_enabled ())
10620                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10621
10622                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10623                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10624                         if (mono_security_core_clr_enabled ())
10625                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10626                         */
10627
10628                         ftype = mono_field_get_type (field);
10629
10630                         /*
10631                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10632                          * the static case.
10633                          */
10634                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
10635                                 switch (op) {
10636                                 case CEE_LDFLD:
10637                                         op = CEE_LDSFLD;
10638                                         break;
10639                                 case CEE_STFLD:
10640                                         op = CEE_STSFLD;
10641                                         break;
10642                                 case CEE_LDFLDA:
10643                                         op = CEE_LDSFLDA;
10644                                         break;
10645                                 default:
10646                                         g_assert_not_reached ();
10647                                 }
10648                                 is_instance = FALSE;
10649                         }
10650
10651                         context_used = mini_class_check_context_used (cfg, klass);
10652
10653                         /* INSTANCE CASE */
10654
10655                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10656                         if (op == CEE_STFLD) {
10657                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10658                                         UNVERIFIED;
10659 #ifndef DISABLE_REMOTING
10660                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10661                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10662                                         MonoInst *iargs [5];
10663
10664                                         GSHAREDVT_FAILURE (op);
10665
10666                                         iargs [0] = sp [0];
10667                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10668                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10669                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10670                                                     field->offset);
10671                                         iargs [4] = sp [1];
10672
10673                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10674                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10675                                                                                            iargs, ip, cfg->real_offset, TRUE);
10676                                                 CHECK_CFG_EXCEPTION;
10677                                                 g_assert (costs > 0);
10678                                                       
10679                                                 cfg->real_offset += 5;
10680
10681                                                 inline_costs += costs;
10682                                         } else {
10683                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10684                                         }
10685                                 } else
10686 #endif
10687                                 {
10688                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
10689
10690                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10691
10692                                         if (ins_flag & MONO_INST_VOLATILE) {
10693                                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10694                                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10695                                         }
10696
10697                                         if (mini_is_gsharedvt_klass (klass)) {
10698                                                 MonoInst *offset_ins;
10699
10700                                                 context_used = mini_class_check_context_used (cfg, klass);
10701
10702                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10703                                                 /* The value is offset by 1 */
10704                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10705                                                 dreg = alloc_ireg_mp (cfg);
10706                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10707                                                 wbarrier_ptr_ins = ins;
10708                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10709                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10710                                         } else {
10711                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10712                                         }
10713                                         if (sp [0]->opcode != OP_LDADDR)
10714                                                 store->flags |= MONO_INST_FAULT;
10715
10716                                         if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
10717                                                 if (mini_is_gsharedvt_klass (klass)) {
10718                                                         g_assert (wbarrier_ptr_ins);
10719                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
10720                                                 } else {
10721                                                         /* insert call to write barrier */
10722                                                         MonoInst *ptr;
10723                                                         int dreg;
10724
10725                                                         dreg = alloc_ireg_mp (cfg);
10726                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10727                                                         emit_write_barrier (cfg, ptr, sp [1]);
10728                                                 }
10729                                         }
10730
10731                                         store->flags |= ins_flag;
10732                                 }
10733                                 ins_flag = 0;
10734                                 ip += 5;
10735                                 break;
10736                         }
10737
10738 #ifndef DISABLE_REMOTING
10739                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10740                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10741                                 MonoInst *iargs [4];
10742
10743                                 GSHAREDVT_FAILURE (op);
10744
10745                                 iargs [0] = sp [0];
10746                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10747                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10748                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10749                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10750                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10751                                                                                    iargs, ip, cfg->real_offset, TRUE);
10752                                         CHECK_CFG_EXCEPTION;
10753                                         g_assert (costs > 0);
10754                                                       
10755                                         cfg->real_offset += 5;
10756
10757                                         *sp++ = iargs [0];
10758
10759                                         inline_costs += costs;
10760                                 } else {
10761                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10762                                         *sp++ = ins;
10763                                 }
10764                         } else 
10765 #endif
10766                         if (is_instance) {
10767                                 if (sp [0]->type == STACK_VTYPE) {
10768                                         MonoInst *var;
10769
10770                                         /* Have to compute the address of the variable */
10771
10772                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10773                                         if (!var)
10774                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10775                                         else
10776                                                 g_assert (var->klass == klass);
10777                                         
10778                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10779                                         sp [0] = ins;
10780                                 }
10781
10782                                 if (op == CEE_LDFLDA) {
10783                                         if (sp [0]->type == STACK_OBJ) {
10784                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10785                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10786                                         }
10787
10788                                         dreg = alloc_ireg_mp (cfg);
10789
10790                                         if (mini_is_gsharedvt_klass (klass)) {
10791                                                 MonoInst *offset_ins;
10792
10793                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10794                                                 /* The value is offset by 1 */
10795                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10796                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10797                                         } else {
10798                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10799                                         }
10800                                         ins->klass = mono_class_from_mono_type (field->type);
10801                                         ins->type = STACK_MP;
10802                                         *sp++ = ins;
10803                                 } else {
10804                                         MonoInst *load;
10805
10806                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10807
10808                                         if (sp [0]->opcode == OP_LDADDR && klass->simd_type && cfg->opt & MONO_OPT_SIMD) {
10809                                                 ins = mono_emit_simd_field_load (cfg, field, sp [0]);
10810                                                 if (ins) {
10811                                                         *sp++ = ins;
10812                                                         ins_flag = 0;
10813                                                         ip += 5;
10814                                                         break;
10815                                                 }
10816                                         }
10817
10818                                         if (mini_is_gsharedvt_klass (klass)) {
10819                                                 MonoInst *offset_ins;
10820
10821                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10822                                                 /* The value is offset by 1 */
10823                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10824                                                 dreg = alloc_ireg_mp (cfg);
10825                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10826                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10827                                         } else {
10828                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10829                                         }
10830                                         load->flags |= ins_flag;
10831                                         if (sp [0]->opcode != OP_LDADDR)
10832                                                 load->flags |= MONO_INST_FAULT;
10833                                         *sp++ = load;
10834                                 }
10835                         }
10836
10837                         if (is_instance) {
10838                                 ins_flag = 0;
10839                                 ip += 5;
10840                                 break;
10841                         }
10842
10843                         /* STATIC CASE */
10844                         context_used = mini_class_check_context_used (cfg, klass);
10845
10846                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
10847                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
10848                                 CHECK_CFG_ERROR;
10849                         }
10850
10851                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10852                          * to be called here.
10853                          */
10854                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10855                                 mono_class_vtable (cfg->domain, klass);
10856                                 CHECK_TYPELOAD (klass);
10857                         }
10858                         mono_domain_lock (cfg->domain);
10859                         if (cfg->domain->special_static_fields)
10860                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10861                         mono_domain_unlock (cfg->domain);
10862
10863                         is_special_static = mono_class_field_is_special_static (field);
10864
10865                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10866                                 thread_ins = mono_create_tls_get (cfg, TLS_KEY_THREAD);
10867                         else
10868                                 thread_ins = NULL;
10869
10870                         /* Generate IR to compute the field address */
10871                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10872                                 /*
10873                                  * Fast access to TLS data
10874                                  * Inline version of get_thread_static_data () in
10875                                  * threads.c.
10876                                  */
10877                                 guint32 offset;
10878                                 int idx, static_data_reg, array_reg, dreg;
10879
10880                                 if (context_used && cfg->gsharedvt && mini_is_gsharedvt_klass (klass))
10881                                         GSHAREDVT_FAILURE (op);
10882
10883                                 static_data_reg = alloc_ireg (cfg);
10884                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
10885
10886                                 if (cfg->compile_aot) {
10887                                         int offset_reg, offset2_reg, idx_reg;
10888
10889                                         /* For TLS variables, this will return the TLS offset */
10890                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10891                                         offset_reg = ins->dreg;
10892                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10893                                         idx_reg = alloc_ireg (cfg);
10894                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
10895                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10896                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10897                                         array_reg = alloc_ireg (cfg);
10898                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10899                                         offset2_reg = alloc_ireg (cfg);
10900                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
10901                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
10902                                         dreg = alloc_ireg (cfg);
10903                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10904                                 } else {
10905                                         offset = (gsize)addr & 0x7fffffff;
10906                                         idx = offset & 0x3f;
10907
10908                                         array_reg = alloc_ireg (cfg);
10909                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10910                                         dreg = alloc_ireg (cfg);
10911                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
10912                                 }
10913                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10914                                         (cfg->compile_aot && is_special_static) ||
10915                                         (context_used && is_special_static)) {
10916                                 MonoInst *iargs [2];
10917
10918                                 g_assert (field->parent);
10919                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10920                                 if (context_used) {
10921                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10922                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10923                                 } else {
10924                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10925                                 }
10926                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10927                         } else if (context_used) {
10928                                 MonoInst *static_data;
10929
10930                                 /*
10931                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10932                                         method->klass->name_space, method->klass->name, method->name,
10933                                         depth, field->offset);
10934                                 */
10935
10936                                 if (mono_class_needs_cctor_run (klass, method))
10937                                         emit_class_init (cfg, klass);
10938
10939                                 /*
10940                                  * The pointer we're computing here is
10941                                  *
10942                                  *   super_info.static_data + field->offset
10943                                  */
10944                                 static_data = mini_emit_get_rgctx_klass (cfg, context_used,
10945                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10946
10947                                 if (mini_is_gsharedvt_klass (klass)) {
10948                                         MonoInst *offset_ins;
10949
10950                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10951                                         /* The value is offset by 1 */
10952                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10953                                         dreg = alloc_ireg_mp (cfg);
10954                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10955                                 } else if (field->offset == 0) {
10956                                         ins = static_data;
10957                                 } else {
10958                                         int addr_reg = mono_alloc_preg (cfg);
10959                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10960                                 }
10961                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10962                                 MonoInst *iargs [2];
10963
10964                                 g_assert (field->parent);
10965                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10966                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10967                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10968                         } else {
10969                                 MonoVTable *vtable = NULL;
10970
10971                                 if (!cfg->compile_aot)
10972                                         vtable = mono_class_vtable (cfg->domain, klass);
10973                                 CHECK_TYPELOAD (klass);
10974
10975                                 if (!addr) {
10976                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10977                                                 if (!(g_slist_find (class_inits, klass))) {
10978                                                         emit_class_init (cfg, klass);
10979                                                         if (cfg->verbose_level > 2)
10980                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10981                                                         class_inits = g_slist_prepend (class_inits, klass);
10982                                                 }
10983                                         } else {
10984                                                 if (cfg->run_cctors) {
10985                                                         /* This makes so that inline cannot trigger */
10986                                                         /* .cctors: too many apps depend on them */
10987                                                         /* running with a specific order... */
10988                                                         g_assert (vtable);
10989                                                         if (! vtable->initialized)
10990                                                                 INLINE_FAILURE ("class init");
10991                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
10992                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
10993                                                                 goto exception_exit;
10994                                                         }
10995                                                 }
10996                                         }
10997                                         if (cfg->compile_aot)
10998                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10999                                         else {
11000                                                 g_assert (vtable);
11001                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11002                                                 g_assert (addr);
11003                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11004                                         }
11005                                 } else {
11006                                         MonoInst *iargs [1];
11007                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11008                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11009                                 }
11010                         }
11011
11012                         /* Generate IR to do the actual load/store operation */
11013
11014                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11015                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11016                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11017                         }
11018
11019                         if (op == CEE_LDSFLDA) {
11020                                 ins->klass = mono_class_from_mono_type (ftype);
11021                                 ins->type = STACK_PTR;
11022                                 *sp++ = ins;
11023                         } else if (op == CEE_STSFLD) {
11024                                 MonoInst *store;
11025
11026                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11027                                 store->flags |= ins_flag;
11028                         } else {
11029                                 gboolean is_const = FALSE;
11030                                 MonoVTable *vtable = NULL;
11031                                 gpointer addr = NULL;
11032
11033                                 if (!context_used) {
11034                                         vtable = mono_class_vtable (cfg->domain, klass);
11035                                         CHECK_TYPELOAD (klass);
11036                                 }
11037                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11038                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11039                                         int ro_type = ftype->type;
11040                                         if (!addr)
11041                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11042                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11043                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11044                                         }
11045
11046                                         GSHAREDVT_FAILURE (op);
11047
11048                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11049                                         is_const = TRUE;
11050                                         switch (ro_type) {
11051                                         case MONO_TYPE_BOOLEAN:
11052                                         case MONO_TYPE_U1:
11053                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11054                                                 sp++;
11055                                                 break;
11056                                         case MONO_TYPE_I1:
11057                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11058                                                 sp++;
11059                                                 break;                                          
11060                                         case MONO_TYPE_CHAR:
11061                                         case MONO_TYPE_U2:
11062                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11063                                                 sp++;
11064                                                 break;
11065                                         case MONO_TYPE_I2:
11066                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11067                                                 sp++;
11068                                                 break;
11069                                                 break;
11070                                         case MONO_TYPE_I4:
11071                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11072                                                 sp++;
11073                                                 break;                                          
11074                                         case MONO_TYPE_U4:
11075                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11076                                                 sp++;
11077                                                 break;
11078                                         case MONO_TYPE_I:
11079                                         case MONO_TYPE_U:
11080                                         case MONO_TYPE_PTR:
11081                                         case MONO_TYPE_FNPTR:
11082                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11083                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11084                                                 sp++;
11085                                                 break;
11086                                         case MONO_TYPE_STRING:
11087                                         case MONO_TYPE_OBJECT:
11088                                         case MONO_TYPE_CLASS:
11089                                         case MONO_TYPE_SZARRAY:
11090                                         case MONO_TYPE_ARRAY:
11091                                                 if (!mono_gc_is_moving ()) {
11092                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11093                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11094                                                         sp++;
11095                                                 } else {
11096                                                         is_const = FALSE;
11097                                                 }
11098                                                 break;
11099                                         case MONO_TYPE_I8:
11100                                         case MONO_TYPE_U8:
11101                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11102                                                 sp++;
11103                                                 break;
11104                                         case MONO_TYPE_R4:
11105                                         case MONO_TYPE_R8:
11106                                         case MONO_TYPE_VALUETYPE:
11107                                         default:
11108                                                 is_const = FALSE;
11109                                                 break;
11110                                         }
11111                                 }
11112
11113                                 if (!is_const) {
11114                                         MonoInst *load;
11115
11116                                         CHECK_STACK_OVF (1);
11117
11118                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11119                                         load->flags |= ins_flag;
11120                                         ins_flag = 0;
11121                                         *sp++ = load;
11122                                 }
11123                         }
11124
11125                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11126                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11127                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11128                         }
11129
11130                         ins_flag = 0;
11131                         ip += 5;
11132                         break;
11133                 }
11134                 case CEE_STOBJ:
11135                         CHECK_STACK (2);
11136                         sp -= 2;
11137                         CHECK_OPSIZE (5);
11138                         token = read32 (ip + 1);
11139                         klass = mini_get_class (method, token, generic_context);
11140                         CHECK_TYPELOAD (klass);
11141                         if (ins_flag & MONO_INST_VOLATILE) {
11142                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11143                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11144                         }
11145                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11146                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11147                         ins->flags |= ins_flag;
11148                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11149                                 generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
11150                                 /* insert call to write barrier */
11151                                 emit_write_barrier (cfg, sp [0], sp [1]);
11152                         }
11153                         ins_flag = 0;
11154                         ip += 5;
11155                         inline_costs += 1;
11156                         break;
11157
11158                         /*
11159                          * Array opcodes
11160                          */
11161                 case CEE_NEWARR: {
11162                         MonoInst *len_ins;
11163                         const char *data_ptr;
11164                         int data_size = 0;
11165                         guint32 field_token;
11166
11167                         CHECK_STACK (1);
11168                         --sp;
11169
11170                         CHECK_OPSIZE (5);
11171                         token = read32 (ip + 1);
11172
11173                         klass = mini_get_class (method, token, generic_context);
11174                         CHECK_TYPELOAD (klass);
11175
11176                         context_used = mini_class_check_context_used (cfg, klass);
11177
11178                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11179                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11180                                 ins->sreg1 = sp [0]->dreg;
11181                                 ins->type = STACK_I4;
11182                                 ins->dreg = alloc_ireg (cfg);
11183                                 MONO_ADD_INS (cfg->cbb, ins);
11184                                 *sp = mono_decompose_opcode (cfg, ins);
11185                         }
11186
11187                         if (context_used) {
11188                                 MonoInst *args [3];
11189                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11190                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11191
11192                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11193
11194                                 /* vtable */
11195                                 args [0] = mini_emit_get_rgctx_klass (cfg, context_used,
11196                                         array_class, MONO_RGCTX_INFO_VTABLE);
11197                                 /* array len */
11198                                 args [1] = sp [0];
11199
11200                                 if (managed_alloc)
11201                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11202                                 else
11203                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11204                         } else {
11205                                 if (cfg->opt & MONO_OPT_SHARED) {
11206                                         /* Decompose now to avoid problems with references to the domainvar */
11207                                         MonoInst *iargs [3];
11208
11209                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11210                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11211                                         iargs [2] = sp [0];
11212
11213                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11214                                 } else {
11215                                         /* Decompose later since it is needed by abcrem */
11216                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11217                                         mono_class_vtable (cfg->domain, array_type);
11218                                         CHECK_TYPELOAD (array_type);
11219
11220                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11221                                         ins->dreg = alloc_ireg_ref (cfg);
11222                                         ins->sreg1 = sp [0]->dreg;
11223                                         ins->inst_newa_class = klass;
11224                                         ins->type = STACK_OBJ;
11225                                         ins->klass = array_type;
11226                                         MONO_ADD_INS (cfg->cbb, ins);
11227                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11228                                         cfg->cbb->has_array_access = TRUE;
11229
11230                                         /* Needed so mono_emit_load_get_addr () gets called */
11231                                         mono_get_got_var (cfg);
11232                                 }
11233                         }
11234
11235                         len_ins = sp [0];
11236                         ip += 5;
11237                         *sp++ = ins;
11238                         inline_costs += 1;
11239
11240                         /* 
11241                          * we inline/optimize the initialization sequence if possible.
11242                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11243                          * for small sizes open code the memcpy
11244                          * ensure the rva field is big enough
11245                          */
11246                         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))) {
11247                                 MonoMethod *memcpy_method = get_memcpy_method ();
11248                                 MonoInst *iargs [3];
11249                                 int add_reg = alloc_ireg_mp (cfg);
11250
11251                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11252                                 if (cfg->compile_aot) {
11253                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11254                                 } else {
11255                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11256                                 }
11257                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11258                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11259                                 ip += 11;
11260                         }
11261
11262                         break;
11263                 }
11264                 case CEE_LDLEN:
11265                         CHECK_STACK (1);
11266                         --sp;
11267                         if (sp [0]->type != STACK_OBJ)
11268                                 UNVERIFIED;
11269
11270                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11271                         ins->dreg = alloc_preg (cfg);
11272                         ins->sreg1 = sp [0]->dreg;
11273                         ins->type = STACK_I4;
11274                         /* This flag will be inherited by the decomposition */
11275                         ins->flags |= MONO_INST_FAULT;
11276                         MONO_ADD_INS (cfg->cbb, ins);
11277                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11278                         cfg->cbb->has_array_access = TRUE;
11279                         ip ++;
11280                         *sp++ = ins;
11281                         break;
11282                 case CEE_LDELEMA:
11283                         CHECK_STACK (2);
11284                         sp -= 2;
11285                         CHECK_OPSIZE (5);
11286                         if (sp [0]->type != STACK_OBJ)
11287                                 UNVERIFIED;
11288
11289                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11290
11291                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11292                         CHECK_TYPELOAD (klass);
11293                         /* we need to make sure that this array is exactly the type it needs
11294                          * to be for correctness. the wrappers are lax with their usage
11295                          * so we need to ignore them here
11296                          */
11297                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11298                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11299                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11300                                 CHECK_TYPELOAD (array_class);
11301                         }
11302
11303                         readonly = FALSE;
11304                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11305                         *sp++ = ins;
11306                         ip += 5;
11307                         break;
11308                 case CEE_LDELEM:
11309                 case CEE_LDELEM_I1:
11310                 case CEE_LDELEM_U1:
11311                 case CEE_LDELEM_I2:
11312                 case CEE_LDELEM_U2:
11313                 case CEE_LDELEM_I4:
11314                 case CEE_LDELEM_U4:
11315                 case CEE_LDELEM_I8:
11316                 case CEE_LDELEM_I:
11317                 case CEE_LDELEM_R4:
11318                 case CEE_LDELEM_R8:
11319                 case CEE_LDELEM_REF: {
11320                         MonoInst *addr;
11321
11322                         CHECK_STACK (2);
11323                         sp -= 2;
11324
11325                         if (*ip == CEE_LDELEM) {
11326                                 CHECK_OPSIZE (5);
11327                                 token = read32 (ip + 1);
11328                                 klass = mini_get_class (method, token, generic_context);
11329                                 CHECK_TYPELOAD (klass);
11330                                 mono_class_init (klass);
11331                         }
11332                         else
11333                                 klass = array_access_to_klass (*ip);
11334
11335                         if (sp [0]->type != STACK_OBJ)
11336                                 UNVERIFIED;
11337
11338                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11339
11340                         if (mini_is_gsharedvt_variable_klass (klass)) {
11341                                 // FIXME-VT: OP_ICONST optimization
11342                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11343                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11344                                 ins->opcode = OP_LOADV_MEMBASE;
11345                         } else if (sp [1]->opcode == OP_ICONST) {
11346                                 int array_reg = sp [0]->dreg;
11347                                 int index_reg = sp [1]->dreg;
11348                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11349
11350                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
11351                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
11352
11353                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11354                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11355                         } else {
11356                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11357                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11358                         }
11359                         *sp++ = ins;
11360                         if (*ip == CEE_LDELEM)
11361                                 ip += 5;
11362                         else
11363                                 ++ip;
11364                         break;
11365                 }
11366                 case CEE_STELEM_I:
11367                 case CEE_STELEM_I1:
11368                 case CEE_STELEM_I2:
11369                 case CEE_STELEM_I4:
11370                 case CEE_STELEM_I8:
11371                 case CEE_STELEM_R4:
11372                 case CEE_STELEM_R8:
11373                 case CEE_STELEM_REF:
11374                 case CEE_STELEM: {
11375                         CHECK_STACK (3);
11376                         sp -= 3;
11377
11378                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11379
11380                         if (*ip == CEE_STELEM) {
11381                                 CHECK_OPSIZE (5);
11382                                 token = read32 (ip + 1);
11383                                 klass = mini_get_class (method, token, generic_context);
11384                                 CHECK_TYPELOAD (klass);
11385                                 mono_class_init (klass);
11386                         }
11387                         else
11388                                 klass = array_access_to_klass (*ip);
11389
11390                         if (sp [0]->type != STACK_OBJ)
11391                                 UNVERIFIED;
11392
11393                         emit_array_store (cfg, klass, sp, TRUE);
11394
11395                         if (*ip == CEE_STELEM)
11396                                 ip += 5;
11397                         else
11398                                 ++ip;
11399                         inline_costs += 1;
11400                         break;
11401                 }
11402                 case CEE_CKFINITE: {
11403                         CHECK_STACK (1);
11404                         --sp;
11405
11406                         if (cfg->llvm_only) {
11407                                 MonoInst *iargs [1];
11408
11409                                 iargs [0] = sp [0];
11410                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11411                         } else  {
11412                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11413                                 ins->sreg1 = sp [0]->dreg;
11414                                 ins->dreg = alloc_freg (cfg);
11415                                 ins->type = STACK_R8;
11416                                 MONO_ADD_INS (cfg->cbb, ins);
11417
11418                                 *sp++ = mono_decompose_opcode (cfg, ins);
11419                         }
11420
11421                         ++ip;
11422                         break;
11423                 }
11424                 case CEE_REFANYVAL: {
11425                         MonoInst *src_var, *src;
11426
11427                         int klass_reg = alloc_preg (cfg);
11428                         int dreg = alloc_preg (cfg);
11429
11430                         GSHAREDVT_FAILURE (*ip);
11431
11432                         CHECK_STACK (1);
11433                         MONO_INST_NEW (cfg, ins, *ip);
11434                         --sp;
11435                         CHECK_OPSIZE (5);
11436                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11437                         CHECK_TYPELOAD (klass);
11438
11439                         context_used = mini_class_check_context_used (cfg, klass);
11440
11441                         // FIXME:
11442                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11443                         if (!src_var)
11444                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11445                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11446                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11447
11448                         if (context_used) {
11449                                 MonoInst *klass_ins;
11450
11451                                 klass_ins = mini_emit_get_rgctx_klass (cfg, context_used,
11452                                                 klass, MONO_RGCTX_INFO_KLASS);
11453
11454                                 // FIXME:
11455                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11456                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11457                         } else {
11458                                 mini_emit_class_check (cfg, klass_reg, klass);
11459                         }
11460                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11461                         ins->type = STACK_MP;
11462                         ins->klass = klass;
11463                         *sp++ = ins;
11464                         ip += 5;
11465                         break;
11466                 }
11467                 case CEE_MKREFANY: {
11468                         MonoInst *loc, *addr;
11469
11470                         GSHAREDVT_FAILURE (*ip);
11471
11472                         CHECK_STACK (1);
11473                         MONO_INST_NEW (cfg, ins, *ip);
11474                         --sp;
11475                         CHECK_OPSIZE (5);
11476                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11477                         CHECK_TYPELOAD (klass);
11478
11479                         context_used = mini_class_check_context_used (cfg, klass);
11480
11481                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11482                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11483
11484                         if (context_used) {
11485                                 MonoInst *const_ins;
11486                                 int type_reg = alloc_preg (cfg);
11487
11488                                 const_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11489                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11490                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11491                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11492                         } else {
11493                                 int const_reg = alloc_preg (cfg);
11494                                 int type_reg = alloc_preg (cfg);
11495
11496                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11497                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11498                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11499                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11500                         }
11501                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11502
11503                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11504                         ins->type = STACK_VTYPE;
11505                         ins->klass = mono_defaults.typed_reference_class;
11506                         *sp++ = ins;
11507                         ip += 5;
11508                         break;
11509                 }
11510                 case CEE_LDTOKEN: {
11511                         gpointer handle;
11512                         MonoClass *handle_class;
11513
11514                         CHECK_STACK_OVF (1);
11515
11516                         CHECK_OPSIZE (5);
11517                         n = read32 (ip + 1);
11518
11519                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11520                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11521                                 handle = mono_method_get_wrapper_data (method, n);
11522                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
11523                                 if (handle_class == mono_defaults.typehandle_class)
11524                                         handle = &((MonoClass*)handle)->byval_arg;
11525                         }
11526                         else {
11527                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11528                                 CHECK_CFG_ERROR;
11529                         }
11530                         if (!handle)
11531                                 LOAD_ERROR;
11532                         mono_class_init (handle_class);
11533                         if (cfg->gshared) {
11534                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11535                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11536                                         /* This case handles ldtoken
11537                                            of an open type, like for
11538                                            typeof(Gen<>). */
11539                                         context_used = 0;
11540                                 } else if (handle_class == mono_defaults.typehandle_class) {
11541                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
11542                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11543                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11544                                 else if (handle_class == mono_defaults.methodhandle_class)
11545                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
11546                                 else
11547                                         g_assert_not_reached ();
11548                         }
11549
11550                         if ((cfg->opt & MONO_OPT_SHARED) &&
11551                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11552                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11553                                 MonoInst *addr, *vtvar, *iargs [3];
11554                                 int method_context_used;
11555
11556                                 method_context_used = mini_method_check_context_used (cfg, method);
11557
11558                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11559
11560                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11561                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11562                                 if (method_context_used) {
11563                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11564                                                 method, MONO_RGCTX_INFO_METHOD);
11565                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11566                                 } else {
11567                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11568                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11569                                 }
11570                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11571
11572                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11573
11574                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11575                         } else {
11576                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11577                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11578                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11579                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11580                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11581                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
11582
11583                                         mono_class_init (tclass);
11584                                         if (context_used) {
11585                                                 ins = mini_emit_get_rgctx_klass (cfg, context_used,
11586                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11587                                         } else if (cfg->compile_aot) {
11588                                                 if (method->wrapper_type) {
11589                                                         error_init (&error); //got to do it since there are multiple conditionals below
11590                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11591                                                                 /* Special case for static synchronized wrappers */
11592                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11593                                                         } else {
11594                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11595                                                                 /* FIXME: n is not a normal token */
11596                                                                 DISABLE_AOT (cfg);
11597                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11598                                                         }
11599                                                 } else {
11600                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11601                                                 }
11602                                         } else {
11603                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
11604                                                 CHECK_CFG_ERROR;
11605                                                 EMIT_NEW_PCONST (cfg, ins, rt);
11606                                         }
11607                                         ins->type = STACK_OBJ;
11608                                         ins->klass = cmethod->klass;
11609                                         ip += 5;
11610                                 } else {
11611                                         MonoInst *addr, *vtvar;
11612
11613                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11614
11615                                         if (context_used) {
11616                                                 if (handle_class == mono_defaults.typehandle_class) {
11617                                                         ins = mini_emit_get_rgctx_klass (cfg, context_used,
11618                                                                         mono_class_from_mono_type ((MonoType *)handle),
11619                                                                         MONO_RGCTX_INFO_TYPE);
11620                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11621                                                         ins = emit_get_rgctx_method (cfg, context_used,
11622                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
11623                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11624                                                         ins = emit_get_rgctx_field (cfg, context_used,
11625                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
11626                                                 } else {
11627                                                         g_assert_not_reached ();
11628                                                 }
11629                                         } else if (cfg->compile_aot) {
11630                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11631                                         } else {
11632                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11633                                         }
11634                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11635                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11636                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11637                                 }
11638                         }
11639
11640                         *sp++ = ins;
11641                         ip += 5;
11642                         break;
11643                 }
11644                 case CEE_THROW:
11645                         CHECK_STACK (1);
11646                         if (sp [-1]->type != STACK_OBJ)
11647                                 UNVERIFIED;
11648
11649                         MONO_INST_NEW (cfg, ins, OP_THROW);
11650                         --sp;
11651                         ins->sreg1 = sp [0]->dreg;
11652                         ip++;
11653                         cfg->cbb->out_of_line = TRUE;
11654                         MONO_ADD_INS (cfg->cbb, ins);
11655                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11656                         MONO_ADD_INS (cfg->cbb, ins);
11657                         sp = stack_start;
11658                         
11659                         link_bblock (cfg, cfg->cbb, end_bblock);
11660                         start_new_bblock = 1;
11661                         /* This can complicate code generation for llvm since the return value might not be defined */
11662                         if (COMPILE_LLVM (cfg))
11663                                 INLINE_FAILURE ("throw");
11664                         break;
11665                 case CEE_ENDFINALLY:
11666                         if (!ip_in_finally_clause (cfg, ip - header->code))
11667                                 UNVERIFIED;
11668                         /* mono_save_seq_point_info () depends on this */
11669                         if (sp != stack_start)
11670                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11671                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11672                         MONO_ADD_INS (cfg->cbb, ins);
11673                         ip++;
11674                         start_new_bblock = 1;
11675
11676                         /*
11677                          * Control will leave the method so empty the stack, otherwise
11678                          * the next basic block will start with a nonempty stack.
11679                          */
11680                         while (sp != stack_start) {
11681                                 sp--;
11682                         }
11683                         break;
11684                 case CEE_LEAVE:
11685                 case CEE_LEAVE_S: {
11686                         GList *handlers;
11687
11688                         if (*ip == CEE_LEAVE) {
11689                                 CHECK_OPSIZE (5);
11690                                 target = ip + 5 + (gint32)read32(ip + 1);
11691                         } else {
11692                                 CHECK_OPSIZE (2);
11693                                 target = ip + 2 + (signed char)(ip [1]);
11694                         }
11695
11696                         /* empty the stack */
11697                         while (sp != stack_start) {
11698                                 sp--;
11699                         }
11700
11701                         /* 
11702                          * If this leave statement is in a catch block, check for a
11703                          * pending exception, and rethrow it if necessary.
11704                          * We avoid doing this in runtime invoke wrappers, since those are called
11705                          * by native code which excepts the wrapper to catch all exceptions.
11706                          */
11707                         for (i = 0; i < header->num_clauses; ++i) {
11708                                 MonoExceptionClause *clause = &header->clauses [i];
11709
11710                                 /* 
11711                                  * Use <= in the final comparison to handle clauses with multiple
11712                                  * leave statements, like in bug #78024.
11713                                  * The ordering of the exception clauses guarantees that we find the
11714                                  * innermost clause.
11715                                  */
11716                                 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) {
11717                                         MonoInst *exc_ins;
11718                                         MonoBasicBlock *dont_throw;
11719
11720                                         /*
11721                                           MonoInst *load;
11722
11723                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11724                                         */
11725
11726                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11727
11728                                         NEW_BBLOCK (cfg, dont_throw);
11729
11730                                         /*
11731                                          * Currently, we always rethrow the abort exception, despite the 
11732                                          * fact that this is not correct. See thread6.cs for an example. 
11733                                          * But propagating the abort exception is more important than 
11734                                          * getting the sematics right.
11735                                          */
11736                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11737                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11738                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11739
11740                                         MONO_START_BB (cfg, dont_throw);
11741                                 }
11742                         }
11743
11744 #ifdef ENABLE_LLVM
11745                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
11746 #endif
11747
11748                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11749                                 GList *tmp;
11750                                 MonoExceptionClause *clause;
11751
11752                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11753                                         clause = (MonoExceptionClause *)tmp->data;
11754                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11755                                         g_assert (tblock);
11756                                         link_bblock (cfg, cfg->cbb, tblock);
11757                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11758                                         ins->inst_target_bb = tblock;
11759                                         ins->inst_eh_block = clause;
11760                                         MONO_ADD_INS (cfg->cbb, ins);
11761                                         cfg->cbb->has_call_handler = 1;
11762                                         if (COMPILE_LLVM (cfg)) {
11763                                                 MonoBasicBlock *target_bb;
11764
11765                                                 /* 
11766                                                  * Link the finally bblock with the target, since it will
11767                                                  * conceptually branch there.
11768                                                  */
11769                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
11770                                                 GET_BBLOCK (cfg, target_bb, target);
11771                                                 link_bblock (cfg, tblock, target_bb);
11772                                         }
11773                                 }
11774                                 g_list_free (handlers);
11775                         } 
11776
11777                         MONO_INST_NEW (cfg, ins, OP_BR);
11778                         MONO_ADD_INS (cfg->cbb, ins);
11779                         GET_BBLOCK (cfg, tblock, target);
11780                         link_bblock (cfg, cfg->cbb, tblock);
11781                         ins->inst_target_bb = tblock;
11782
11783                         start_new_bblock = 1;
11784
11785                         if (*ip == CEE_LEAVE)
11786                                 ip += 5;
11787                         else
11788                                 ip += 2;
11789
11790                         break;
11791                 }
11792
11793                         /*
11794                          * Mono specific opcodes
11795                          */
11796                 case MONO_CUSTOM_PREFIX: {
11797
11798                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11799
11800                         CHECK_OPSIZE (2);
11801                         switch (ip [1]) {
11802                         case CEE_MONO_ICALL: {
11803                                 gpointer func;
11804                                 MonoJitICallInfo *info;
11805
11806                                 token = read32 (ip + 2);
11807                                 func = mono_method_get_wrapper_data (method, token);
11808                                 info = mono_find_jit_icall_by_addr (func);
11809                                 if (!info)
11810                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11811                                 g_assert (info);
11812
11813                                 CHECK_STACK (info->sig->param_count);
11814                                 sp -= info->sig->param_count;
11815
11816                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11817                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11818                                         *sp++ = ins;
11819
11820                                 ip += 6;
11821                                 inline_costs += 10 * num_calls++;
11822
11823                                 break;
11824                         }
11825                         case CEE_MONO_LDPTR_CARD_TABLE:
11826                         case CEE_MONO_LDPTR_NURSERY_START:
11827                         case CEE_MONO_LDPTR_NURSERY_BITS:
11828                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
11829                                 CHECK_STACK_OVF (1);
11830
11831                                 switch (ip [1]) {
11832                                         case CEE_MONO_LDPTR_CARD_TABLE:
11833                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
11834                                                 break;
11835                                         case CEE_MONO_LDPTR_NURSERY_START:
11836                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
11837                                                 break;
11838                                         case CEE_MONO_LDPTR_NURSERY_BITS:
11839                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
11840                                                 break;
11841                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
11842                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11843                                                 break;
11844                                 }
11845
11846                                 *sp++ = ins;
11847                                 ip += 2;
11848                                 inline_costs += 10 * num_calls++;
11849                                 break;
11850                         }
11851                         case CEE_MONO_LDPTR: {
11852                                 gpointer ptr;
11853
11854                                 CHECK_STACK_OVF (1);
11855                                 CHECK_OPSIZE (6);
11856                                 token = read32 (ip + 2);
11857
11858                                 ptr = mono_method_get_wrapper_data (method, token);
11859                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11860                                 *sp++ = ins;
11861                                 ip += 6;
11862                                 inline_costs += 10 * num_calls++;
11863                                 /* Can't embed random pointers into AOT code */
11864                                 DISABLE_AOT (cfg);
11865                                 break;
11866                         }
11867                         case CEE_MONO_JIT_ICALL_ADDR: {
11868                                 MonoJitICallInfo *callinfo;
11869                                 gpointer ptr;
11870
11871                                 CHECK_STACK_OVF (1);
11872                                 CHECK_OPSIZE (6);
11873                                 token = read32 (ip + 2);
11874
11875                                 ptr = mono_method_get_wrapper_data (method, token);
11876                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11877                                 g_assert (callinfo);
11878                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11879                                 *sp++ = ins;
11880                                 ip += 6;
11881                                 inline_costs += 10 * num_calls++;
11882                                 break;
11883                         }
11884                         case CEE_MONO_ICALL_ADDR: {
11885                                 MonoMethod *cmethod;
11886                                 gpointer ptr;
11887
11888                                 CHECK_STACK_OVF (1);
11889                                 CHECK_OPSIZE (6);
11890                                 token = read32 (ip + 2);
11891
11892                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
11893
11894                                 if (cfg->compile_aot) {
11895                                         if (cfg->direct_pinvoke && ip + 6 < end && (ip [6] == CEE_POP)) {
11896                                                 /*
11897                                                  * This is generated by emit_native_wrapper () to resolve the pinvoke address
11898                                                  * before the call, its not needed when using direct pinvoke.
11899                                                  * This is not an optimization, but its used to avoid looking up pinvokes
11900                                                  * on platforms which don't support dlopen ().
11901                                                  */
11902                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11903                                         } else {
11904                                                 EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11905                                         }
11906                                 } else {
11907                                         ptr = mono_lookup_internal_call (cmethod);
11908                                         g_assert (ptr);
11909                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11910                                 }
11911                                 *sp++ = ins;
11912                                 ip += 6;
11913                                 break;
11914                         }
11915                         case CEE_MONO_VTADDR: {
11916                                 MonoInst *src_var, *src;
11917
11918                                 CHECK_STACK (1);
11919                                 --sp;
11920
11921                                 // FIXME:
11922                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11923                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11924                                 *sp++ = src;
11925                                 ip += 2;
11926                                 break;
11927                         }
11928                         case CEE_MONO_NEWOBJ: {
11929                                 MonoInst *iargs [2];
11930
11931                                 CHECK_STACK_OVF (1);
11932                                 CHECK_OPSIZE (6);
11933                                 token = read32 (ip + 2);
11934                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11935                                 mono_class_init (klass);
11936                                 NEW_DOMAINCONST (cfg, iargs [0]);
11937                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11938                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11939                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11940                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
11941                                 ip += 6;
11942                                 inline_costs += 10 * num_calls++;
11943                                 break;
11944                         }
11945                         case CEE_MONO_OBJADDR:
11946                                 CHECK_STACK (1);
11947                                 --sp;
11948                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11949                                 ins->dreg = alloc_ireg_mp (cfg);
11950                                 ins->sreg1 = sp [0]->dreg;
11951                                 ins->type = STACK_MP;
11952                                 MONO_ADD_INS (cfg->cbb, ins);
11953                                 *sp++ = ins;
11954                                 ip += 2;
11955                                 break;
11956                         case CEE_MONO_LDNATIVEOBJ:
11957                                 /*
11958                                  * Similar to LDOBJ, but instead load the unmanaged 
11959                                  * representation of the vtype to the stack.
11960                                  */
11961                                 CHECK_STACK (1);
11962                                 CHECK_OPSIZE (6);
11963                                 --sp;
11964                                 token = read32 (ip + 2);
11965                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11966                                 g_assert (klass->valuetype);
11967                                 mono_class_init (klass);
11968
11969                                 {
11970                                         MonoInst *src, *dest, *temp;
11971
11972                                         src = sp [0];
11973                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11974                                         temp->backend.is_pinvoke = 1;
11975                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11976                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11977
11978                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11979                                         dest->type = STACK_VTYPE;
11980                                         dest->klass = klass;
11981
11982                                         *sp ++ = dest;
11983                                         ip += 6;
11984                                 }
11985                                 break;
11986                         case CEE_MONO_RETOBJ: {
11987                                 /*
11988                                  * Same as RET, but return the native representation of a vtype
11989                                  * to the caller.
11990                                  */
11991                                 g_assert (cfg->ret);
11992                                 g_assert (mono_method_signature (method)->pinvoke); 
11993                                 CHECK_STACK (1);
11994                                 --sp;
11995                                 
11996                                 CHECK_OPSIZE (6);
11997                                 token = read32 (ip + 2);    
11998                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11999
12000                                 if (!cfg->vret_addr) {
12001                                         g_assert (cfg->ret_var_is_local);
12002
12003                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12004                                 } else {
12005                                         EMIT_NEW_RETLOADA (cfg, ins);
12006                                 }
12007                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12008                                 
12009                                 if (sp != stack_start)
12010                                         UNVERIFIED;
12011                                 
12012                                 MONO_INST_NEW (cfg, ins, OP_BR);
12013                                 ins->inst_target_bb = end_bblock;
12014                                 MONO_ADD_INS (cfg->cbb, ins);
12015                                 link_bblock (cfg, cfg->cbb, end_bblock);
12016                                 start_new_bblock = 1;
12017                                 ip += 6;
12018                                 break;
12019                         }
12020                         case CEE_MONO_SAVE_LMF:
12021                         case CEE_MONO_RESTORE_LMF:
12022                                 ip += 2;
12023                                 break;
12024                         case CEE_MONO_CLASSCONST:
12025                                 CHECK_STACK_OVF (1);
12026                                 CHECK_OPSIZE (6);
12027                                 token = read32 (ip + 2);
12028                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12029                                 *sp++ = ins;
12030                                 ip += 6;
12031                                 inline_costs += 10 * num_calls++;
12032                                 break;
12033                         case CEE_MONO_NOT_TAKEN:
12034                                 cfg->cbb->out_of_line = TRUE;
12035                                 ip += 2;
12036                                 break;
12037                         case CEE_MONO_TLS: {
12038                                 MonoTlsKey key;
12039
12040                                 CHECK_STACK_OVF (1);
12041                                 CHECK_OPSIZE (6);
12042                                 key = (MonoTlsKey)read32 (ip + 2);
12043                                 g_assert (key < TLS_KEY_NUM);
12044
12045                                 ins = mono_create_tls_get (cfg, key);
12046                                 g_assert (ins);
12047                                 ins->type = STACK_PTR;
12048                                 *sp++ = ins;
12049                                 ip += 6;
12050                                 break;
12051                         }
12052                         case CEE_MONO_DYN_CALL: {
12053                                 MonoCallInst *call;
12054
12055                                 /* It would be easier to call a trampoline, but that would put an
12056                                  * extra frame on the stack, confusing exception handling. So
12057                                  * implement it inline using an opcode for now.
12058                                  */
12059
12060                                 if (!cfg->dyn_call_var) {
12061                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12062                                         /* prevent it from being register allocated */
12063                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12064                                 }
12065
12066                                 /* Has to use a call inst since it local regalloc expects it */
12067                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12068                                 ins = (MonoInst*)call;
12069                                 sp -= 2;
12070                                 ins->sreg1 = sp [0]->dreg;
12071                                 ins->sreg2 = sp [1]->dreg;
12072                                 MONO_ADD_INS (cfg->cbb, ins);
12073
12074                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12075
12076                                 ip += 2;
12077                                 inline_costs += 10 * num_calls++;
12078
12079                                 break;
12080                         }
12081                         case CEE_MONO_MEMORY_BARRIER: {
12082                                 CHECK_OPSIZE (6);
12083                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12084                                 ip += 6;
12085                                 break;
12086                         }
12087                         case CEE_MONO_ATOMIC_STORE_I4: {
12088                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
12089
12090                                 CHECK_OPSIZE (6);
12091                                 CHECK_STACK (2);
12092                                 sp -= 2;
12093
12094                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
12095                                 ins->dreg = sp [0]->dreg;
12096                                 ins->sreg1 = sp [1]->dreg;
12097                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
12098                                 MONO_ADD_INS (cfg->cbb, ins);
12099
12100                                 ip += 6;
12101                                 break;
12102                         }
12103                         case CEE_MONO_JIT_ATTACH: {
12104                                 MonoInst *args [16], *domain_ins;
12105                                 MonoInst *ad_ins, *jit_tls_ins;
12106                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12107
12108                                 g_assert (!mono_threads_is_coop_enabled ());
12109
12110                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12111
12112                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12113                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12114
12115                                 ad_ins = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
12116                                 jit_tls_ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
12117
12118                                 if (ad_ins && jit_tls_ins) {
12119                                         NEW_BBLOCK (cfg, next_bb);
12120                                         NEW_BBLOCK (cfg, call_bb);
12121
12122                                         if (cfg->compile_aot) {
12123                                                 /* AOT code is only used in the root domain */
12124                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12125                                         } else {
12126                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12127                                         }
12128                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12129                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12130
12131                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12132                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12133
12134                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12135                                         MONO_START_BB (cfg, call_bb);
12136                                 }
12137
12138                                 /* AOT code is only used in the root domain */
12139                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12140                                 if (cfg->compile_aot) {
12141                                         MonoInst *addr;
12142
12143                                         /*
12144                                          * This is called on unattached threads, so it cannot go through the trampoline
12145                                          * infrastructure. Use an indirect call through a got slot initialized at load time
12146                                          * instead.
12147                                          */
12148                                         EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_JIT_THREAD_ATTACH, NULL);
12149                                         ins = mono_emit_calli (cfg, helper_sig_jit_thread_attach, args, addr, NULL, NULL);
12150                                 } else {
12151                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12152                                 }
12153                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12154
12155                                 if (next_bb)
12156                                         MONO_START_BB (cfg, next_bb);
12157
12158                                 ip += 2;
12159                                 break;
12160                         }
12161                         case CEE_MONO_JIT_DETACH: {
12162                                 MonoInst *args [16];
12163
12164                                 /* Restore the original domain */
12165                                 dreg = alloc_ireg (cfg);
12166                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12167                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12168                                 ip += 2;
12169                                 break;
12170                         }
12171                         case CEE_MONO_CALLI_EXTRA_ARG: {
12172                                 MonoInst *addr;
12173                                 MonoMethodSignature *fsig;
12174                                 MonoInst *arg;
12175
12176                                 /*
12177                                  * This is the same as CEE_CALLI, but passes an additional argument
12178                                  * to the called method in llvmonly mode.
12179                                  * This is only used by delegate invoke wrappers to call the
12180                                  * actual delegate method.
12181                                  */
12182                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12183
12184                                 CHECK_OPSIZE (6);
12185                                 token = read32 (ip + 2);
12186
12187                                 ins = NULL;
12188
12189                                 cmethod = NULL;
12190                                 CHECK_STACK (1);
12191                                 --sp;
12192                                 addr = *sp;
12193                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12194                                 CHECK_CFG_ERROR;
12195
12196                                 if (cfg->llvm_only)
12197                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12198
12199                                 n = fsig->param_count + fsig->hasthis + 1;
12200
12201                                 CHECK_STACK (n);
12202
12203                                 sp -= n;
12204                                 arg = sp [n - 1];
12205
12206                                 if (cfg->llvm_only) {
12207                                         /*
12208                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12209                                          * cconv. This is set by mono_init_delegate ().
12210                                          */
12211                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12212                                                 MonoInst *callee = addr;
12213                                                 MonoInst *call, *localloc_ins;
12214                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12215                                                 int low_bit_reg = alloc_preg (cfg);
12216
12217                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12218                                                 NEW_BBLOCK (cfg, end_bb);
12219
12220                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12221                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12222                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12223
12224                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12225                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12226                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12227                                                 /*
12228                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12229                                                  */
12230                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12231                                                 ins->dreg = alloc_preg (cfg);
12232                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12233                                                 MONO_ADD_INS (cfg->cbb, ins);
12234                                                 localloc_ins = ins;
12235                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12236                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12237                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12238
12239                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12240                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12241
12242                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12243                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12244                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12245                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12246                                                 ins->dreg = call->dreg;
12247
12248                                                 MONO_START_BB (cfg, end_bb);
12249                                         } else {
12250                                                 /* Caller uses a normal calling conv */
12251
12252                                                 MonoInst *callee = addr;
12253                                                 MonoInst *call, *localloc_ins;
12254                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12255                                                 int low_bit_reg = alloc_preg (cfg);
12256
12257                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12258                                                 NEW_BBLOCK (cfg, end_bb);
12259
12260                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12261                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12262                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12263
12264                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12265                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12266                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12267                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12268                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12269                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12270                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12271                                                 MONO_ADD_INS (cfg->cbb, addr);
12272                                                 /*
12273                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12274                                                  */
12275                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12276                                                 ins->dreg = alloc_preg (cfg);
12277                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12278                                                 MONO_ADD_INS (cfg->cbb, ins);
12279                                                 localloc_ins = ins;
12280                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12281                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12282                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12283
12284                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12285                                                 ins->dreg = call->dreg;
12286                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12287
12288                                                 MONO_START_BB (cfg, end_bb);
12289                                         }
12290                                 } else {
12291                                         /* Same as CEE_CALLI */
12292                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12293                                                 /*
12294                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12295                                                  */
12296                                                 MonoInst *callee = addr;
12297
12298                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12299                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12300                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12301                                         } else {
12302                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12303                                         }
12304                                 }
12305
12306                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12307                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12308
12309                                 CHECK_CFG_EXCEPTION;
12310
12311                                 ip += 6;
12312                                 ins_flag = 0;
12313                                 constrained_class = NULL;
12314                                 break;
12315                         }
12316                         case CEE_MONO_LDDOMAIN:
12317                                 CHECK_STACK_OVF (1);
12318                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
12319                                 ip += 2;
12320                                 *sp++ = ins;
12321                                 break;
12322                         case CEE_MONO_GET_LAST_ERROR:
12323                                 CHECK_OPSIZE (2);
12324                                 CHECK_STACK_OVF (1);
12325
12326                                 MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
12327                                 ins->dreg = alloc_dreg (cfg, STACK_I4);
12328                                 ins->type = STACK_I4;
12329                                 MONO_ADD_INS (cfg->cbb, ins);
12330
12331                                 ip += 2;
12332                                 *sp++ = ins;
12333                                 break;
12334                         default:
12335                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12336                                 break;
12337                         }
12338                         break;
12339                 }
12340
12341                 case CEE_PREFIX1: {
12342                         CHECK_OPSIZE (2);
12343                         switch (ip [1]) {
12344                         case CEE_ARGLIST: {
12345                                 /* somewhat similar to LDTOKEN */
12346                                 MonoInst *addr, *vtvar;
12347                                 CHECK_STACK_OVF (1);
12348                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12349
12350                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12351                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12352
12353                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12354                                 ins->type = STACK_VTYPE;
12355                                 ins->klass = mono_defaults.argumenthandle_class;
12356                                 *sp++ = ins;
12357                                 ip += 2;
12358                                 break;
12359                         }
12360                         case CEE_CEQ:
12361                         case CEE_CGT:
12362                         case CEE_CGT_UN:
12363                         case CEE_CLT:
12364                         case CEE_CLT_UN: {
12365                                 MonoInst *cmp, *arg1, *arg2;
12366
12367                                 CHECK_STACK (2);
12368                                 sp -= 2;
12369                                 arg1 = sp [0];
12370                                 arg2 = sp [1];
12371
12372                                 /*
12373                                  * The following transforms:
12374                                  *    CEE_CEQ    into OP_CEQ
12375                                  *    CEE_CGT    into OP_CGT
12376                                  *    CEE_CGT_UN into OP_CGT_UN
12377                                  *    CEE_CLT    into OP_CLT
12378                                  *    CEE_CLT_UN into OP_CLT_UN
12379                                  */
12380                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12381
12382                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12383                                 cmp->sreg1 = arg1->dreg;
12384                                 cmp->sreg2 = arg2->dreg;
12385                                 type_from_op (cfg, cmp, arg1, arg2);
12386                                 CHECK_TYPE (cmp);
12387                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12388                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12389                                         cmp->opcode = OP_LCOMPARE;
12390                                 else if (arg1->type == STACK_R4)
12391                                         cmp->opcode = OP_RCOMPARE;
12392                                 else if (arg1->type == STACK_R8)
12393                                         cmp->opcode = OP_FCOMPARE;
12394                                 else
12395                                         cmp->opcode = OP_ICOMPARE;
12396                                 MONO_ADD_INS (cfg->cbb, cmp);
12397                                 ins->type = STACK_I4;
12398                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
12399                                 type_from_op (cfg, ins, arg1, arg2);
12400
12401                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12402                                         /*
12403                                          * The backends expect the fceq opcodes to do the
12404                                          * comparison too.
12405                                          */
12406                                         ins->sreg1 = cmp->sreg1;
12407                                         ins->sreg2 = cmp->sreg2;
12408                                         NULLIFY_INS (cmp);
12409                                 }
12410                                 MONO_ADD_INS (cfg->cbb, ins);
12411                                 *sp++ = ins;
12412                                 ip += 2;
12413                                 break;
12414                         }
12415                         case CEE_LDFTN: {
12416                                 MonoInst *argconst;
12417                                 MonoMethod *cil_method;
12418
12419                                 CHECK_STACK_OVF (1);
12420                                 CHECK_OPSIZE (6);
12421                                 n = read32 (ip + 2);
12422                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12423                                 CHECK_CFG_ERROR;
12424
12425                                 mono_class_init (cmethod->klass);
12426
12427                                 mono_save_token_info (cfg, image, n, cmethod);
12428
12429                                 context_used = mini_method_check_context_used (cfg, cmethod);
12430
12431                                 cil_method = cmethod;
12432                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12433                                         emit_method_access_failure (cfg, method, cil_method);
12434
12435                                 if (mono_security_core_clr_enabled ())
12436                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12437
12438                                 /* 
12439                                  * Optimize the common case of ldftn+delegate creation
12440                                  */
12441                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12442                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12443                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12444                                                 MonoInst *target_ins, *handle_ins;
12445                                                 MonoMethod *invoke;
12446                                                 int invoke_context_used;
12447
12448                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12449                                                 if (!invoke || !mono_method_signature (invoke))
12450                                                         LOAD_ERROR;
12451
12452                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12453
12454                                                 target_ins = sp [-1];
12455
12456                                                 if (mono_security_core_clr_enabled ())
12457                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12458
12459                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12460                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12461                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12462                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12463                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12464                                                         }
12465                                                 }
12466
12467                                                 /* FIXME: SGEN support */
12468                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12469                                                         ip += 6;
12470                                                         if (cfg->verbose_level > 3)
12471                                                                 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));
12472                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12473                                                                 sp --;
12474                                                                 *sp = handle_ins;
12475                                                                 CHECK_CFG_EXCEPTION;
12476                                                                 ip += 5;
12477                                                                 sp ++;
12478                                                                 break;
12479                                                         }
12480                                                         ip -= 6;
12481                                                 }
12482                                         }
12483                                 }
12484
12485                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12486                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12487                                 *sp++ = ins;
12488                                 
12489                                 ip += 6;
12490                                 inline_costs += 10 * num_calls++;
12491                                 break;
12492                         }
12493                         case CEE_LDVIRTFTN: {
12494                                 MonoInst *args [2];
12495
12496                                 CHECK_STACK (1);
12497                                 CHECK_OPSIZE (6);
12498                                 n = read32 (ip + 2);
12499                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12500                                 CHECK_CFG_ERROR;
12501
12502                                 mono_class_init (cmethod->klass);
12503  
12504                                 context_used = mini_method_check_context_used (cfg, cmethod);
12505
12506                                 if (mono_security_core_clr_enabled ())
12507                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12508
12509                                 /*
12510                                  * Optimize the common case of ldvirtftn+delegate creation
12511                                  */
12512                                 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)) {
12513                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12514                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12515                                                 MonoInst *target_ins, *handle_ins;
12516                                                 MonoMethod *invoke;
12517                                                 int invoke_context_used;
12518                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12519
12520                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12521                                                 if (!invoke || !mono_method_signature (invoke))
12522                                                         LOAD_ERROR;
12523
12524                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12525
12526                                                 target_ins = sp [-1];
12527
12528                                                 if (mono_security_core_clr_enabled ())
12529                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12530
12531                                                 /* FIXME: SGEN support */
12532                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12533                                                         ip += 6;
12534                                                         if (cfg->verbose_level > 3)
12535                                                                 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));
12536                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12537                                                                 sp -= 2;
12538                                                                 *sp = handle_ins;
12539                                                                 CHECK_CFG_EXCEPTION;
12540                                                                 ip += 5;
12541                                                                 sp ++;
12542                                                                 break;
12543                                                         }
12544                                                         ip -= 6;
12545                                                 }
12546                                         }
12547                                 }
12548
12549                                 --sp;
12550                                 args [0] = *sp;
12551
12552                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12553                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12554
12555                                 if (context_used)
12556                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12557                                 else
12558                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12559
12560                                 ip += 6;
12561                                 inline_costs += 10 * num_calls++;
12562                                 break;
12563                         }
12564                         case CEE_LDARG:
12565                                 CHECK_STACK_OVF (1);
12566                                 CHECK_OPSIZE (4);
12567                                 n = read16 (ip + 2);
12568                                 CHECK_ARG (n);
12569                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12570                                 *sp++ = ins;
12571                                 ip += 4;
12572                                 break;
12573                         case CEE_LDARGA:
12574                                 CHECK_STACK_OVF (1);
12575                                 CHECK_OPSIZE (4);
12576                                 n = read16 (ip + 2);
12577                                 CHECK_ARG (n);
12578                                 NEW_ARGLOADA (cfg, ins, n);
12579                                 MONO_ADD_INS (cfg->cbb, ins);
12580                                 *sp++ = ins;
12581                                 ip += 4;
12582                                 break;
12583                         case CEE_STARG:
12584                                 CHECK_STACK (1);
12585                                 --sp;
12586                                 CHECK_OPSIZE (4);
12587                                 n = read16 (ip + 2);
12588                                 CHECK_ARG (n);
12589                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12590                                         UNVERIFIED;
12591                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12592                                 ip += 4;
12593                                 break;
12594                         case CEE_LDLOC:
12595                                 CHECK_STACK_OVF (1);
12596                                 CHECK_OPSIZE (4);
12597                                 n = read16 (ip + 2);
12598                                 CHECK_LOCAL (n);
12599                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12600                                 *sp++ = ins;
12601                                 ip += 4;
12602                                 break;
12603                         case CEE_LDLOCA: {
12604                                 unsigned char *tmp_ip;
12605                                 CHECK_STACK_OVF (1);
12606                                 CHECK_OPSIZE (4);
12607                                 n = read16 (ip + 2);
12608                                 CHECK_LOCAL (n);
12609
12610                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12611                                         ip = tmp_ip;
12612                                         inline_costs += 1;
12613                                         break;
12614                                 }                       
12615                                 
12616                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12617                                 *sp++ = ins;
12618                                 ip += 4;
12619                                 break;
12620                         }
12621                         case CEE_STLOC:
12622                                 CHECK_STACK (1);
12623                                 --sp;
12624                                 CHECK_OPSIZE (4);
12625                                 n = read16 (ip + 2);
12626                                 CHECK_LOCAL (n);
12627                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12628                                         UNVERIFIED;
12629                                 emit_stloc_ir (cfg, sp, header, n);
12630                                 ip += 4;
12631                                 inline_costs += 1;
12632                                 break;
12633                         case CEE_LOCALLOC: {
12634                                 CHECK_STACK (1);
12635                                 MonoBasicBlock *non_zero_bb, *end_bb;
12636                                 int alloc_ptr = alloc_preg (cfg);
12637                                 --sp;
12638                                 if (sp != stack_start) 
12639                                         UNVERIFIED;
12640                                 if (cfg->method != method) 
12641                                         /* 
12642                                          * Inlining this into a loop in a parent could lead to 
12643                                          * stack overflows which is different behavior than the
12644                                          * non-inlined case, thus disable inlining in this case.
12645                                          */
12646                                         INLINE_FAILURE("localloc");
12647
12648                                 NEW_BBLOCK (cfg, non_zero_bb);
12649                                 NEW_BBLOCK (cfg, end_bb);
12650
12651                                 /* if size != zero */
12652                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
12653                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
12654
12655                                 //size is zero, so result is NULL
12656                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
12657                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12658
12659                                 MONO_START_BB (cfg, non_zero_bb);
12660                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12661                                 ins->dreg = alloc_ptr;
12662                                 ins->sreg1 = sp [0]->dreg;
12663                                 ins->type = STACK_PTR;
12664                                 MONO_ADD_INS (cfg->cbb, ins);
12665
12666                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12667                                 if (init_locals)
12668                                         ins->flags |= MONO_INST_INIT;
12669
12670                                 MONO_START_BB (cfg, end_bb);
12671                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
12672                                 ins->type = STACK_PTR;
12673
12674                                 *sp++ = ins;
12675                                 ip += 2;
12676                                 break;
12677                         }
12678                         case CEE_ENDFILTER: {
12679                                 MonoExceptionClause *clause, *nearest;
12680                                 int cc;
12681
12682                                 CHECK_STACK (1);
12683                                 --sp;
12684                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12685                                         UNVERIFIED;
12686                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12687                                 ins->sreg1 = (*sp)->dreg;
12688                                 MONO_ADD_INS (cfg->cbb, ins);
12689                                 start_new_bblock = 1;
12690                                 ip += 2;
12691
12692                                 nearest = NULL;
12693                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12694                                         clause = &header->clauses [cc];
12695                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12696                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12697                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12698                                                 nearest = clause;
12699                                 }
12700                                 g_assert (nearest);
12701                                 if ((ip - header->code) != nearest->handler_offset)
12702                                         UNVERIFIED;
12703
12704                                 break;
12705                         }
12706                         case CEE_UNALIGNED_:
12707                                 ins_flag |= MONO_INST_UNALIGNED;
12708                                 /* FIXME: record alignment? we can assume 1 for now */
12709                                 CHECK_OPSIZE (3);
12710                                 ip += 3;
12711                                 break;
12712                         case CEE_VOLATILE_:
12713                                 ins_flag |= MONO_INST_VOLATILE;
12714                                 ip += 2;
12715                                 break;
12716                         case CEE_TAIL_:
12717                                 ins_flag   |= MONO_INST_TAILCALL;
12718                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12719                                 /* Can't inline tail calls at this time */
12720                                 inline_costs += 100000;
12721                                 ip += 2;
12722                                 break;
12723                         case CEE_INITOBJ:
12724                                 CHECK_STACK (1);
12725                                 --sp;
12726                                 CHECK_OPSIZE (6);
12727                                 token = read32 (ip + 2);
12728                                 klass = mini_get_class (method, token, generic_context);
12729                                 CHECK_TYPELOAD (klass);
12730                                 if (generic_class_is_reference_type (cfg, klass))
12731                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12732                                 else
12733                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12734                                 ip += 6;
12735                                 inline_costs += 1;
12736                                 break;
12737                         case CEE_CONSTRAINED_:
12738                                 CHECK_OPSIZE (6);
12739                                 token = read32 (ip + 2);
12740                                 constrained_class = mini_get_class (method, token, generic_context);
12741                                 CHECK_TYPELOAD (constrained_class);
12742                                 ip += 6;
12743                                 break;
12744                         case CEE_CPBLK:
12745                         case CEE_INITBLK: {
12746                                 MonoInst *iargs [3];
12747                                 CHECK_STACK (3);
12748                                 sp -= 3;
12749
12750                                 /* Skip optimized paths for volatile operations. */
12751                                 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)) {
12752                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12753                                 } 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)) {
12754                                         /* emit_memset only works when val == 0 */
12755                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12756                                 } else {
12757                                         MonoInst *call;
12758                                         iargs [0] = sp [0];
12759                                         iargs [1] = sp [1];
12760                                         iargs [2] = sp [2];
12761                                         if (ip [1] == CEE_CPBLK) {
12762                                                 /*
12763                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12764                                                  * and release barriers for cpblk. It is technically both a load and
12765                                                  * store operation, so it seems like that's the sensible thing to do.
12766                                                  *
12767                                                  * FIXME: We emit full barriers on both sides of the operation for
12768                                                  * simplicity. We should have a separate atomic memcpy method instead.
12769                                                  */
12770                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12771
12772                                                 if (ins_flag & MONO_INST_VOLATILE)
12773                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12774
12775                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12776                                                 call->flags |= ins_flag;
12777
12778                                                 if (ins_flag & MONO_INST_VOLATILE)
12779                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12780                                         } else {
12781                                                 MonoMethod *memset_method = get_memset_method ();
12782                                                 if (ins_flag & MONO_INST_VOLATILE) {
12783                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12784                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12785                                                 }
12786                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12787                                                 call->flags |= ins_flag;
12788                                         }
12789                                 }
12790                                 ip += 2;
12791                                 ins_flag = 0;
12792                                 inline_costs += 1;
12793                                 break;
12794                         }
12795                         case CEE_NO_:
12796                                 CHECK_OPSIZE (3);
12797                                 if (ip [2] & 0x1)
12798                                         ins_flag |= MONO_INST_NOTYPECHECK;
12799                                 if (ip [2] & 0x2)
12800                                         ins_flag |= MONO_INST_NORANGECHECK;
12801                                 /* we ignore the no-nullcheck for now since we
12802                                  * really do it explicitly only when doing callvirt->call
12803                                  */
12804                                 ip += 3;
12805                                 break;
12806                         case CEE_RETHROW: {
12807                                 MonoInst *load;
12808                                 int handler_offset = -1;
12809
12810                                 for (i = 0; i < header->num_clauses; ++i) {
12811                                         MonoExceptionClause *clause = &header->clauses [i];
12812                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12813                                                 handler_offset = clause->handler_offset;
12814                                                 break;
12815                                         }
12816                                 }
12817
12818                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12819
12820                                 if (handler_offset == -1)
12821                                         UNVERIFIED;
12822
12823                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12824                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12825                                 ins->sreg1 = load->dreg;
12826                                 MONO_ADD_INS (cfg->cbb, ins);
12827
12828                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12829                                 MONO_ADD_INS (cfg->cbb, ins);
12830
12831                                 sp = stack_start;
12832                                 link_bblock (cfg, cfg->cbb, end_bblock);
12833                                 start_new_bblock = 1;
12834                                 ip += 2;
12835                                 break;
12836                         }
12837                         case CEE_SIZEOF: {
12838                                 guint32 val;
12839                                 int ialign;
12840
12841                                 CHECK_STACK_OVF (1);
12842                                 CHECK_OPSIZE (6);
12843                                 token = read32 (ip + 2);
12844                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12845                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12846                                         CHECK_CFG_ERROR;
12847
12848                                         val = mono_type_size (type, &ialign);
12849                                 } else {
12850                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12851                                         CHECK_TYPELOAD (klass);
12852
12853                                         val = mono_type_size (&klass->byval_arg, &ialign);
12854
12855                                         if (mini_is_gsharedvt_klass (klass))
12856                                                 GSHAREDVT_FAILURE (*ip);
12857                                 }
12858                                 EMIT_NEW_ICONST (cfg, ins, val);
12859                                 *sp++= ins;
12860                                 ip += 6;
12861                                 break;
12862                         }
12863                         case CEE_REFANYTYPE: {
12864                                 MonoInst *src_var, *src;
12865
12866                                 GSHAREDVT_FAILURE (*ip);
12867
12868                                 CHECK_STACK (1);
12869                                 --sp;
12870
12871                                 // FIXME:
12872                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12873                                 if (!src_var)
12874                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12875                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12876                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12877                                 *sp++ = ins;
12878                                 ip += 2;
12879                                 break;
12880                         }
12881                         case CEE_READONLY_:
12882                                 readonly = TRUE;
12883                                 ip += 2;
12884                                 break;
12885
12886                         case CEE_UNUSED56:
12887                         case CEE_UNUSED57:
12888                         case CEE_UNUSED70:
12889                         case CEE_UNUSED:
12890                         case CEE_UNUSED99:
12891                                 UNVERIFIED;
12892                                 
12893                         default:
12894                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12895                                 UNVERIFIED;
12896                         }
12897                         break;
12898                 }
12899                 case CEE_UNUSED58:
12900                 case CEE_UNUSED1:
12901                         UNVERIFIED;
12902
12903                 default:
12904                         g_warning ("opcode 0x%02x not handled", *ip);
12905                         UNVERIFIED;
12906                 }
12907         }
12908         if (start_new_bblock != 1)
12909                 UNVERIFIED;
12910
12911         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
12912         if (cfg->cbb->next_bb) {
12913                 /* This could already be set because of inlining, #693905 */
12914                 MonoBasicBlock *bb = cfg->cbb;
12915
12916                 while (bb->next_bb)
12917                         bb = bb->next_bb;
12918                 bb->next_bb = end_bblock;
12919         } else {
12920                 cfg->cbb->next_bb = end_bblock;
12921         }
12922
12923         if (cfg->method == method && cfg->domainvar) {
12924                 MonoInst *store;
12925                 MonoInst *get_domain;
12926
12927                 cfg->cbb = init_localsbb;
12928
12929                 get_domain = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
12930                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12931                 MONO_ADD_INS (cfg->cbb, store);
12932         }
12933
12934 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12935         if (cfg->compile_aot)
12936                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12937                 mono_get_got_var (cfg);
12938 #endif
12939
12940         if (cfg->method == method && cfg->got_var)
12941                 mono_emit_load_got_addr (cfg);
12942
12943         if (init_localsbb) {
12944                 cfg->cbb = init_localsbb;
12945                 cfg->ip = NULL;
12946                 for (i = 0; i < header->num_locals; ++i) {
12947                         emit_init_local (cfg, i, header->locals [i], init_locals);
12948                 }
12949         }
12950
12951         if (cfg->init_ref_vars && cfg->method == method) {
12952                 /* Emit initialization for ref vars */
12953                 // FIXME: Avoid duplication initialization for IL locals.
12954                 for (i = 0; i < cfg->num_varinfo; ++i) {
12955                         MonoInst *ins = cfg->varinfo [i];
12956
12957                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12958                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12959                 }
12960         }
12961
12962         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
12963                 cfg->cbb = init_localsbb;
12964                 emit_push_lmf (cfg);
12965         }
12966
12967         cfg->cbb = init_localsbb;
12968         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12969
12970         if (seq_points) {
12971                 MonoBasicBlock *bb;
12972
12973                 /*
12974                  * Make seq points at backward branch targets interruptable.
12975                  */
12976                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12977                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12978                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12979         }
12980
12981         /* Add a sequence point for method entry/exit events */
12982         if (seq_points && cfg->gen_sdb_seq_points) {
12983                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12984                 MONO_ADD_INS (init_localsbb, ins);
12985                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12986                 MONO_ADD_INS (cfg->bb_exit, ins);
12987         }
12988
12989         /*
12990          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12991          * the code they refer to was dead (#11880).
12992          */
12993         if (sym_seq_points) {
12994                 for (i = 0; i < header->code_size; ++i) {
12995                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12996                                 MonoInst *ins;
12997
12998                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12999                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13000                         }
13001                 }
13002         }
13003
13004         cfg->ip = NULL;
13005
13006         if (cfg->method == method) {
13007                 MonoBasicBlock *bb;
13008                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13009                         if (bb == cfg->bb_init)
13010                                 bb->region = -1;
13011                         else
13012                                 bb->region = mono_find_block_region (cfg, bb->real_offset);
13013                         if (cfg->spvars)
13014                                 mono_create_spvar_for_region (cfg, bb->region);
13015                         if (cfg->verbose_level > 2)
13016                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13017                 }
13018         } else {
13019                 MonoBasicBlock *bb;
13020                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
13021                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
13022                         bb->real_offset = inline_offset;
13023                 }
13024         }
13025
13026         if (inline_costs < 0) {
13027                 char *mname;
13028
13029                 /* Method is too large */
13030                 mname = mono_method_full_name (method, TRUE);
13031                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13032                 g_free (mname);
13033         }
13034
13035         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13036                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13037
13038         goto cleanup;
13039
13040 mono_error_exit:
13041         g_assert (!mono_error_ok (&cfg->error));
13042         goto cleanup;
13043  
13044  exception_exit:
13045         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13046         goto cleanup;
13047
13048  unverified:
13049         set_exception_type_from_invalid_il (cfg, method, ip);
13050         goto cleanup;
13051
13052  cleanup:
13053         g_slist_free (class_inits);
13054         mono_basic_block_free (original_bb);
13055         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13056         if (cfg->exception_type)
13057                 return -1;
13058         else
13059                 return inline_costs;
13060 }
13061
13062 static int
13063 store_membase_reg_to_store_membase_imm (int opcode)
13064 {
13065         switch (opcode) {
13066         case OP_STORE_MEMBASE_REG:
13067                 return OP_STORE_MEMBASE_IMM;
13068         case OP_STOREI1_MEMBASE_REG:
13069                 return OP_STOREI1_MEMBASE_IMM;
13070         case OP_STOREI2_MEMBASE_REG:
13071                 return OP_STOREI2_MEMBASE_IMM;
13072         case OP_STOREI4_MEMBASE_REG:
13073                 return OP_STOREI4_MEMBASE_IMM;
13074         case OP_STOREI8_MEMBASE_REG:
13075                 return OP_STOREI8_MEMBASE_IMM;
13076         default:
13077                 g_assert_not_reached ();
13078         }
13079
13080         return -1;
13081 }               
13082
13083 int
13084 mono_op_to_op_imm (int opcode)
13085 {
13086         switch (opcode) {
13087         case OP_IADD:
13088                 return OP_IADD_IMM;
13089         case OP_ISUB:
13090                 return OP_ISUB_IMM;
13091         case OP_IDIV:
13092                 return OP_IDIV_IMM;
13093         case OP_IDIV_UN:
13094                 return OP_IDIV_UN_IMM;
13095         case OP_IREM:
13096                 return OP_IREM_IMM;
13097         case OP_IREM_UN:
13098                 return OP_IREM_UN_IMM;
13099         case OP_IMUL:
13100                 return OP_IMUL_IMM;
13101         case OP_IAND:
13102                 return OP_IAND_IMM;
13103         case OP_IOR:
13104                 return OP_IOR_IMM;
13105         case OP_IXOR:
13106                 return OP_IXOR_IMM;
13107         case OP_ISHL:
13108                 return OP_ISHL_IMM;
13109         case OP_ISHR:
13110                 return OP_ISHR_IMM;
13111         case OP_ISHR_UN:
13112                 return OP_ISHR_UN_IMM;
13113
13114         case OP_LADD:
13115                 return OP_LADD_IMM;
13116         case OP_LSUB:
13117                 return OP_LSUB_IMM;
13118         case OP_LAND:
13119                 return OP_LAND_IMM;
13120         case OP_LOR:
13121                 return OP_LOR_IMM;
13122         case OP_LXOR:
13123                 return OP_LXOR_IMM;
13124         case OP_LSHL:
13125                 return OP_LSHL_IMM;
13126         case OP_LSHR:
13127                 return OP_LSHR_IMM;
13128         case OP_LSHR_UN:
13129                 return OP_LSHR_UN_IMM;
13130 #if SIZEOF_REGISTER == 8
13131         case OP_LREM:
13132                 return OP_LREM_IMM;
13133 #endif
13134
13135         case OP_COMPARE:
13136                 return OP_COMPARE_IMM;
13137         case OP_ICOMPARE:
13138                 return OP_ICOMPARE_IMM;
13139         case OP_LCOMPARE:
13140                 return OP_LCOMPARE_IMM;
13141
13142         case OP_STORE_MEMBASE_REG:
13143                 return OP_STORE_MEMBASE_IMM;
13144         case OP_STOREI1_MEMBASE_REG:
13145                 return OP_STOREI1_MEMBASE_IMM;
13146         case OP_STOREI2_MEMBASE_REG:
13147                 return OP_STOREI2_MEMBASE_IMM;
13148         case OP_STOREI4_MEMBASE_REG:
13149                 return OP_STOREI4_MEMBASE_IMM;
13150
13151 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13152         case OP_X86_PUSH:
13153                 return OP_X86_PUSH_IMM;
13154         case OP_X86_COMPARE_MEMBASE_REG:
13155                 return OP_X86_COMPARE_MEMBASE_IMM;
13156 #endif
13157 #if defined(TARGET_AMD64)
13158         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13159                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13160 #endif
13161         case OP_VOIDCALL_REG:
13162                 return OP_VOIDCALL;
13163         case OP_CALL_REG:
13164                 return OP_CALL;
13165         case OP_LCALL_REG:
13166                 return OP_LCALL;
13167         case OP_FCALL_REG:
13168                 return OP_FCALL;
13169         case OP_LOCALLOC:
13170                 return OP_LOCALLOC_IMM;
13171         }
13172
13173         return -1;
13174 }
13175
13176 static int
13177 ldind_to_load_membase (int opcode)
13178 {
13179         switch (opcode) {
13180         case CEE_LDIND_I1:
13181                 return OP_LOADI1_MEMBASE;
13182         case CEE_LDIND_U1:
13183                 return OP_LOADU1_MEMBASE;
13184         case CEE_LDIND_I2:
13185                 return OP_LOADI2_MEMBASE;
13186         case CEE_LDIND_U2:
13187                 return OP_LOADU2_MEMBASE;
13188         case CEE_LDIND_I4:
13189                 return OP_LOADI4_MEMBASE;
13190         case CEE_LDIND_U4:
13191                 return OP_LOADU4_MEMBASE;
13192         case CEE_LDIND_I:
13193                 return OP_LOAD_MEMBASE;
13194         case CEE_LDIND_REF:
13195                 return OP_LOAD_MEMBASE;
13196         case CEE_LDIND_I8:
13197                 return OP_LOADI8_MEMBASE;
13198         case CEE_LDIND_R4:
13199                 return OP_LOADR4_MEMBASE;
13200         case CEE_LDIND_R8:
13201                 return OP_LOADR8_MEMBASE;
13202         default:
13203                 g_assert_not_reached ();
13204         }
13205
13206         return -1;
13207 }
13208
13209 static int
13210 stind_to_store_membase (int opcode)
13211 {
13212         switch (opcode) {
13213         case CEE_STIND_I1:
13214                 return OP_STOREI1_MEMBASE_REG;
13215         case CEE_STIND_I2:
13216                 return OP_STOREI2_MEMBASE_REG;
13217         case CEE_STIND_I4:
13218                 return OP_STOREI4_MEMBASE_REG;
13219         case CEE_STIND_I:
13220         case CEE_STIND_REF:
13221                 return OP_STORE_MEMBASE_REG;
13222         case CEE_STIND_I8:
13223                 return OP_STOREI8_MEMBASE_REG;
13224         case CEE_STIND_R4:
13225                 return OP_STORER4_MEMBASE_REG;
13226         case CEE_STIND_R8:
13227                 return OP_STORER8_MEMBASE_REG;
13228         default:
13229                 g_assert_not_reached ();
13230         }
13231
13232         return -1;
13233 }
13234
13235 int
13236 mono_load_membase_to_load_mem (int opcode)
13237 {
13238         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13239 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13240         switch (opcode) {
13241         case OP_LOAD_MEMBASE:
13242                 return OP_LOAD_MEM;
13243         case OP_LOADU1_MEMBASE:
13244                 return OP_LOADU1_MEM;
13245         case OP_LOADU2_MEMBASE:
13246                 return OP_LOADU2_MEM;
13247         case OP_LOADI4_MEMBASE:
13248                 return OP_LOADI4_MEM;
13249         case OP_LOADU4_MEMBASE:
13250                 return OP_LOADU4_MEM;
13251 #if SIZEOF_REGISTER == 8
13252         case OP_LOADI8_MEMBASE:
13253                 return OP_LOADI8_MEM;
13254 #endif
13255         }
13256 #endif
13257
13258         return -1;
13259 }
13260
13261 static inline int
13262 op_to_op_dest_membase (int store_opcode, int opcode)
13263 {
13264 #if defined(TARGET_X86)
13265         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13266                 return -1;
13267
13268         switch (opcode) {
13269         case OP_IADD:
13270                 return OP_X86_ADD_MEMBASE_REG;
13271         case OP_ISUB:
13272                 return OP_X86_SUB_MEMBASE_REG;
13273         case OP_IAND:
13274                 return OP_X86_AND_MEMBASE_REG;
13275         case OP_IOR:
13276                 return OP_X86_OR_MEMBASE_REG;
13277         case OP_IXOR:
13278                 return OP_X86_XOR_MEMBASE_REG;
13279         case OP_ADD_IMM:
13280         case OP_IADD_IMM:
13281                 return OP_X86_ADD_MEMBASE_IMM;
13282         case OP_SUB_IMM:
13283         case OP_ISUB_IMM:
13284                 return OP_X86_SUB_MEMBASE_IMM;
13285         case OP_AND_IMM:
13286         case OP_IAND_IMM:
13287                 return OP_X86_AND_MEMBASE_IMM;
13288         case OP_OR_IMM:
13289         case OP_IOR_IMM:
13290                 return OP_X86_OR_MEMBASE_IMM;
13291         case OP_XOR_IMM:
13292         case OP_IXOR_IMM:
13293                 return OP_X86_XOR_MEMBASE_IMM;
13294         case OP_MOVE:
13295                 return OP_NOP;
13296         }
13297 #endif
13298
13299 #if defined(TARGET_AMD64)
13300         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13301                 return -1;
13302
13303         switch (opcode) {
13304         case OP_IADD:
13305                 return OP_X86_ADD_MEMBASE_REG;
13306         case OP_ISUB:
13307                 return OP_X86_SUB_MEMBASE_REG;
13308         case OP_IAND:
13309                 return OP_X86_AND_MEMBASE_REG;
13310         case OP_IOR:
13311                 return OP_X86_OR_MEMBASE_REG;
13312         case OP_IXOR:
13313                 return OP_X86_XOR_MEMBASE_REG;
13314         case OP_IADD_IMM:
13315                 return OP_X86_ADD_MEMBASE_IMM;
13316         case OP_ISUB_IMM:
13317                 return OP_X86_SUB_MEMBASE_IMM;
13318         case OP_IAND_IMM:
13319                 return OP_X86_AND_MEMBASE_IMM;
13320         case OP_IOR_IMM:
13321                 return OP_X86_OR_MEMBASE_IMM;
13322         case OP_IXOR_IMM:
13323                 return OP_X86_XOR_MEMBASE_IMM;
13324         case OP_LADD:
13325                 return OP_AMD64_ADD_MEMBASE_REG;
13326         case OP_LSUB:
13327                 return OP_AMD64_SUB_MEMBASE_REG;
13328         case OP_LAND:
13329                 return OP_AMD64_AND_MEMBASE_REG;
13330         case OP_LOR:
13331                 return OP_AMD64_OR_MEMBASE_REG;
13332         case OP_LXOR:
13333                 return OP_AMD64_XOR_MEMBASE_REG;
13334         case OP_ADD_IMM:
13335         case OP_LADD_IMM:
13336                 return OP_AMD64_ADD_MEMBASE_IMM;
13337         case OP_SUB_IMM:
13338         case OP_LSUB_IMM:
13339                 return OP_AMD64_SUB_MEMBASE_IMM;
13340         case OP_AND_IMM:
13341         case OP_LAND_IMM:
13342                 return OP_AMD64_AND_MEMBASE_IMM;
13343         case OP_OR_IMM:
13344         case OP_LOR_IMM:
13345                 return OP_AMD64_OR_MEMBASE_IMM;
13346         case OP_XOR_IMM:
13347         case OP_LXOR_IMM:
13348                 return OP_AMD64_XOR_MEMBASE_IMM;
13349         case OP_MOVE:
13350                 return OP_NOP;
13351         }
13352 #endif
13353
13354         return -1;
13355 }
13356
13357 static inline int
13358 op_to_op_store_membase (int store_opcode, int opcode)
13359 {
13360 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13361         switch (opcode) {
13362         case OP_ICEQ:
13363                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13364                         return OP_X86_SETEQ_MEMBASE;
13365         case OP_CNE:
13366                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13367                         return OP_X86_SETNE_MEMBASE;
13368         }
13369 #endif
13370
13371         return -1;
13372 }
13373
13374 static inline int
13375 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13376 {
13377 #ifdef TARGET_X86
13378         /* FIXME: This has sign extension issues */
13379         /*
13380         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13381                 return OP_X86_COMPARE_MEMBASE8_IMM;
13382         */
13383
13384         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13385                 return -1;
13386
13387         switch (opcode) {
13388         case OP_X86_PUSH:
13389                 return OP_X86_PUSH_MEMBASE;
13390         case OP_COMPARE_IMM:
13391         case OP_ICOMPARE_IMM:
13392                 return OP_X86_COMPARE_MEMBASE_IMM;
13393         case OP_COMPARE:
13394         case OP_ICOMPARE:
13395                 return OP_X86_COMPARE_MEMBASE_REG;
13396         }
13397 #endif
13398
13399 #ifdef TARGET_AMD64
13400         /* FIXME: This has sign extension issues */
13401         /*
13402         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13403                 return OP_X86_COMPARE_MEMBASE8_IMM;
13404         */
13405
13406         switch (opcode) {
13407         case OP_X86_PUSH:
13408                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13409                         return OP_X86_PUSH_MEMBASE;
13410                 break;
13411                 /* FIXME: This only works for 32 bit immediates
13412         case OP_COMPARE_IMM:
13413         case OP_LCOMPARE_IMM:
13414                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13415                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13416                 */
13417         case OP_ICOMPARE_IMM:
13418                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13419                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13420                 break;
13421         case OP_COMPARE:
13422         case OP_LCOMPARE:
13423                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
13424                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13425                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13426                         return OP_AMD64_COMPARE_MEMBASE_REG;
13427                 break;
13428         case OP_ICOMPARE:
13429                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13430                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13431                 break;
13432         }
13433 #endif
13434
13435         return -1;
13436 }
13437
13438 static inline int
13439 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
13440 {
13441 #ifdef TARGET_X86
13442         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13443                 return -1;
13444         
13445         switch (opcode) {
13446         case OP_COMPARE:
13447         case OP_ICOMPARE:
13448                 return OP_X86_COMPARE_REG_MEMBASE;
13449         case OP_IADD:
13450                 return OP_X86_ADD_REG_MEMBASE;
13451         case OP_ISUB:
13452                 return OP_X86_SUB_REG_MEMBASE;
13453         case OP_IAND:
13454                 return OP_X86_AND_REG_MEMBASE;
13455         case OP_IOR:
13456                 return OP_X86_OR_REG_MEMBASE;
13457         case OP_IXOR:
13458                 return OP_X86_XOR_REG_MEMBASE;
13459         }
13460 #endif
13461
13462 #ifdef TARGET_AMD64
13463         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
13464                 switch (opcode) {
13465                 case OP_ICOMPARE:
13466                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13467                 case OP_IADD:
13468                         return OP_X86_ADD_REG_MEMBASE;
13469                 case OP_ISUB:
13470                         return OP_X86_SUB_REG_MEMBASE;
13471                 case OP_IAND:
13472                         return OP_X86_AND_REG_MEMBASE;
13473                 case OP_IOR:
13474                         return OP_X86_OR_REG_MEMBASE;
13475                 case OP_IXOR:
13476                         return OP_X86_XOR_REG_MEMBASE;
13477                 }
13478         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
13479                 switch (opcode) {
13480                 case OP_COMPARE:
13481                 case OP_LCOMPARE:
13482                         return OP_AMD64_COMPARE_REG_MEMBASE;
13483                 case OP_LADD:
13484                         return OP_AMD64_ADD_REG_MEMBASE;
13485                 case OP_LSUB:
13486                         return OP_AMD64_SUB_REG_MEMBASE;
13487                 case OP_LAND:
13488                         return OP_AMD64_AND_REG_MEMBASE;
13489                 case OP_LOR:
13490                         return OP_AMD64_OR_REG_MEMBASE;
13491                 case OP_LXOR:
13492                         return OP_AMD64_XOR_REG_MEMBASE;
13493                 }
13494         }
13495 #endif
13496
13497         return -1;
13498 }
13499
13500 int
13501 mono_op_to_op_imm_noemul (int opcode)
13502 {
13503         switch (opcode) {
13504 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13505         case OP_LSHR:
13506         case OP_LSHL:
13507         case OP_LSHR_UN:
13508                 return -1;
13509 #endif
13510 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13511         case OP_IDIV:
13512         case OP_IDIV_UN:
13513         case OP_IREM:
13514         case OP_IREM_UN:
13515                 return -1;
13516 #endif
13517 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13518         case OP_IMUL:
13519                 return -1;
13520 #endif
13521         default:
13522                 return mono_op_to_op_imm (opcode);
13523         }
13524 }
13525
13526 /**
13527  * mono_handle_global_vregs:
13528  *
13529  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13530  * for them.
13531  */
13532 void
13533 mono_handle_global_vregs (MonoCompile *cfg)
13534 {
13535         gint32 *vreg_to_bb;
13536         MonoBasicBlock *bb;
13537         int i, pos;
13538
13539         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13540
13541 #ifdef MONO_ARCH_SIMD_INTRINSICS
13542         if (cfg->uses_simd_intrinsics)
13543                 mono_simd_simplify_indirection (cfg);
13544 #endif
13545
13546         /* Find local vregs used in more than one bb */
13547         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13548                 MonoInst *ins = bb->code;       
13549                 int block_num = bb->block_num;
13550
13551                 if (cfg->verbose_level > 2)
13552                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13553
13554                 cfg->cbb = bb;
13555                 for (; ins; ins = ins->next) {
13556                         const char *spec = INS_INFO (ins->opcode);
13557                         int regtype = 0, regindex;
13558                         gint32 prev_bb;
13559
13560                         if (G_UNLIKELY (cfg->verbose_level > 2))
13561                                 mono_print_ins (ins);
13562
13563                         g_assert (ins->opcode >= MONO_CEE_LAST);
13564
13565                         for (regindex = 0; regindex < 4; regindex ++) {
13566                                 int vreg = 0;
13567
13568                                 if (regindex == 0) {
13569                                         regtype = spec [MONO_INST_DEST];
13570                                         if (regtype == ' ')
13571                                                 continue;
13572                                         vreg = ins->dreg;
13573                                 } else if (regindex == 1) {
13574                                         regtype = spec [MONO_INST_SRC1];
13575                                         if (regtype == ' ')
13576                                                 continue;
13577                                         vreg = ins->sreg1;
13578                                 } else if (regindex == 2) {
13579                                         regtype = spec [MONO_INST_SRC2];
13580                                         if (regtype == ' ')
13581                                                 continue;
13582                                         vreg = ins->sreg2;
13583                                 } else if (regindex == 3) {
13584                                         regtype = spec [MONO_INST_SRC3];
13585                                         if (regtype == ' ')
13586                                                 continue;
13587                                         vreg = ins->sreg3;
13588                                 }
13589
13590 #if SIZEOF_REGISTER == 4
13591                                 /* In the LLVM case, the long opcodes are not decomposed */
13592                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13593                                         /*
13594                                          * Since some instructions reference the original long vreg,
13595                                          * and some reference the two component vregs, it is quite hard
13596                                          * to determine when it needs to be global. So be conservative.
13597                                          */
13598                                         if (!get_vreg_to_inst (cfg, vreg)) {
13599                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13600
13601                                                 if (cfg->verbose_level > 2)
13602                                                         printf ("LONG VREG R%d made global.\n", vreg);
13603                                         }
13604
13605                                         /*
13606                                          * Make the component vregs volatile since the optimizations can
13607                                          * get confused otherwise.
13608                                          */
13609                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
13610                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
13611                                 }
13612 #endif
13613
13614                                 g_assert (vreg != -1);
13615
13616                                 prev_bb = vreg_to_bb [vreg];
13617                                 if (prev_bb == 0) {
13618                                         /* 0 is a valid block num */
13619                                         vreg_to_bb [vreg] = block_num + 1;
13620                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13621                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13622                                                 continue;
13623
13624                                         if (!get_vreg_to_inst (cfg, vreg)) {
13625                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13626                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13627
13628                                                 switch (regtype) {
13629                                                 case 'i':
13630                                                         if (vreg_is_ref (cfg, vreg))
13631                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13632                                                         else
13633                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13634                                                         break;
13635                                                 case 'l':
13636                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13637                                                         break;
13638                                                 case 'f':
13639                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13640                                                         break;
13641                                                 case 'v':
13642                                                 case 'x':
13643                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13644                                                         break;
13645                                                 default:
13646                                                         g_assert_not_reached ();
13647                                                 }
13648                                         }
13649
13650                                         /* Flag as having been used in more than one bb */
13651                                         vreg_to_bb [vreg] = -1;
13652                                 }
13653                         }
13654                 }
13655         }
13656
13657         /* If a variable is used in only one bblock, convert it into a local vreg */
13658         for (i = 0; i < cfg->num_varinfo; i++) {
13659                 MonoInst *var = cfg->varinfo [i];
13660                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13661
13662                 switch (var->type) {
13663                 case STACK_I4:
13664                 case STACK_OBJ:
13665                 case STACK_PTR:
13666                 case STACK_MP:
13667                 case STACK_VTYPE:
13668 #if SIZEOF_REGISTER == 8
13669                 case STACK_I8:
13670 #endif
13671 #if !defined(TARGET_X86)
13672                 /* Enabling this screws up the fp stack on x86 */
13673                 case STACK_R8:
13674 #endif
13675                         if (mono_arch_is_soft_float ())
13676                                 break;
13677
13678                         /*
13679                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
13680                                 break;
13681                         */
13682
13683                         /* Arguments are implicitly global */
13684                         /* Putting R4 vars into registers doesn't work currently */
13685                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13686                         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) {
13687                                 /* 
13688                                  * Make that the variable's liveness interval doesn't contain a call, since
13689                                  * that would cause the lvreg to be spilled, making the whole optimization
13690                                  * useless.
13691                                  */
13692                                 /* This is too slow for JIT compilation */
13693 #if 0
13694                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13695                                         MonoInst *ins;
13696                                         int def_index, call_index, ins_index;
13697                                         gboolean spilled = FALSE;
13698
13699                                         def_index = -1;
13700                                         call_index = -1;
13701                                         ins_index = 0;
13702                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13703                                                 const char *spec = INS_INFO (ins->opcode);
13704
13705                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13706                                                         def_index = ins_index;
13707
13708                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13709                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13710                                                         if (call_index > def_index) {
13711                                                                 spilled = TRUE;
13712                                                                 break;
13713                                                         }
13714                                                 }
13715
13716                                                 if (MONO_IS_CALL (ins))
13717                                                         call_index = ins_index;
13718
13719                                                 ins_index ++;
13720                                         }
13721
13722                                         if (spilled)
13723                                                 break;
13724                                 }
13725 #endif
13726
13727                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13728                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13729                                 var->flags |= MONO_INST_IS_DEAD;
13730                                 cfg->vreg_to_inst [var->dreg] = NULL;
13731                         }
13732                         break;
13733                 }
13734         }
13735
13736         /* 
13737          * Compress the varinfo and vars tables so the liveness computation is faster and
13738          * takes up less space.
13739          */
13740         pos = 0;
13741         for (i = 0; i < cfg->num_varinfo; ++i) {
13742                 MonoInst *var = cfg->varinfo [i];
13743                 if (pos < i && cfg->locals_start == i)
13744                         cfg->locals_start = pos;
13745                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13746                         if (pos < i) {
13747                                 cfg->varinfo [pos] = cfg->varinfo [i];
13748                                 cfg->varinfo [pos]->inst_c0 = pos;
13749                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13750                                 cfg->vars [pos].idx = pos;
13751 #if SIZEOF_REGISTER == 4
13752                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13753                                         /* Modify the two component vars too */
13754                                         MonoInst *var1;
13755
13756                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
13757                                         var1->inst_c0 = pos;
13758                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
13759                                         var1->inst_c0 = pos;
13760                                 }
13761 #endif
13762                         }
13763                         pos ++;
13764                 }
13765         }
13766         cfg->num_varinfo = pos;
13767         if (cfg->locals_start > cfg->num_varinfo)
13768                 cfg->locals_start = cfg->num_varinfo;
13769 }
13770
13771 /*
13772  * mono_allocate_gsharedvt_vars:
13773  *
13774  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
13775  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
13776  */
13777 void
13778 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
13779 {
13780         int i;
13781
13782         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13783
13784         for (i = 0; i < cfg->num_varinfo; ++i) {
13785                 MonoInst *ins = cfg->varinfo [i];
13786                 int idx;
13787
13788                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13789                         if (i >= cfg->locals_start) {
13790                                 /* Local */
13791                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13792                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13793                                 ins->opcode = OP_GSHAREDVT_LOCAL;
13794                                 ins->inst_imm = idx;
13795                         } else {
13796                                 /* Arg */
13797                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
13798                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13799                         }
13800                 }
13801         }
13802 }
13803
13804 /**
13805  * mono_spill_global_vars:
13806  *
13807  *   Generate spill code for variables which are not allocated to registers, 
13808  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13809  * code is generated which could be optimized by the local optimization passes.
13810  */
13811 void
13812 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13813 {
13814         MonoBasicBlock *bb;
13815         char spec2 [16];
13816         int orig_next_vreg;
13817         guint32 *vreg_to_lvreg;
13818         guint32 *lvregs;
13819         guint32 i, lvregs_len, lvregs_size;
13820         gboolean dest_has_lvreg = FALSE;
13821         MonoStackType stacktypes [128];
13822         MonoInst **live_range_start, **live_range_end;
13823         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13824
13825         *need_local_opts = FALSE;
13826
13827         memset (spec2, 0, sizeof (spec2));
13828
13829         /* FIXME: Move this function to mini.c */
13830         stacktypes ['i'] = STACK_PTR;
13831         stacktypes ['l'] = STACK_I8;
13832         stacktypes ['f'] = STACK_R8;
13833 #ifdef MONO_ARCH_SIMD_INTRINSICS
13834         stacktypes ['x'] = STACK_VTYPE;
13835 #endif
13836
13837 #if SIZEOF_REGISTER == 4
13838         /* Create MonoInsts for longs */
13839         for (i = 0; i < cfg->num_varinfo; i++) {
13840                 MonoInst *ins = cfg->varinfo [i];
13841
13842                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13843                         switch (ins->type) {
13844                         case STACK_R8:
13845                         case STACK_I8: {
13846                                 MonoInst *tree;
13847
13848                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13849                                         break;
13850
13851                                 g_assert (ins->opcode == OP_REGOFFSET);
13852
13853                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
13854                                 g_assert (tree);
13855                                 tree->opcode = OP_REGOFFSET;
13856                                 tree->inst_basereg = ins->inst_basereg;
13857                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13858
13859                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
13860                                 g_assert (tree);
13861                                 tree->opcode = OP_REGOFFSET;
13862                                 tree->inst_basereg = ins->inst_basereg;
13863                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13864                                 break;
13865                         }
13866                         default:
13867                                 break;
13868                         }
13869                 }
13870         }
13871 #endif
13872
13873         if (cfg->compute_gc_maps) {
13874                 /* registers need liveness info even for !non refs */
13875                 for (i = 0; i < cfg->num_varinfo; i++) {
13876                         MonoInst *ins = cfg->varinfo [i];
13877
13878                         if (ins->opcode == OP_REGVAR)
13879                                 ins->flags |= MONO_INST_GC_TRACK;
13880                 }
13881         }
13882                 
13883         /* FIXME: widening and truncation */
13884
13885         /*
13886          * As an optimization, when a variable allocated to the stack is first loaded into 
13887          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13888          * the variable again.
13889          */
13890         orig_next_vreg = cfg->next_vreg;
13891         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13892         lvregs_size = 1024;
13893         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * lvregs_size);
13894         lvregs_len = 0;
13895
13896         /* 
13897          * These arrays contain the first and last instructions accessing a given
13898          * variable.
13899          * Since we emit bblocks in the same order we process them here, and we
13900          * don't split live ranges, these will precisely describe the live range of
13901          * the variable, i.e. the instruction range where a valid value can be found
13902          * in the variables location.
13903          * The live range is computed using the liveness info computed by the liveness pass.
13904          * We can't use vmv->range, since that is an abstract live range, and we need
13905          * one which is instruction precise.
13906          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13907          */
13908         /* FIXME: Only do this if debugging info is requested */
13909         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13910         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13911         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13912         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13913         
13914         /* Add spill loads/stores */
13915         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13916                 MonoInst *ins;
13917
13918                 if (cfg->verbose_level > 2)
13919                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13920
13921                 /* Clear vreg_to_lvreg array */
13922                 for (i = 0; i < lvregs_len; i++)
13923                         vreg_to_lvreg [lvregs [i]] = 0;
13924                 lvregs_len = 0;
13925
13926                 cfg->cbb = bb;
13927                 MONO_BB_FOR_EACH_INS (bb, ins) {
13928                         const char *spec = INS_INFO (ins->opcode);
13929                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13930                         gboolean store, no_lvreg;
13931                         int sregs [MONO_MAX_SRC_REGS];
13932
13933                         if (G_UNLIKELY (cfg->verbose_level > 2))
13934                                 mono_print_ins (ins);
13935
13936                         if (ins->opcode == OP_NOP)
13937                                 continue;
13938
13939                         /* 
13940                          * We handle LDADDR here as well, since it can only be decomposed
13941                          * when variable addresses are known.
13942                          */
13943                         if (ins->opcode == OP_LDADDR) {
13944                                 MonoInst *var = (MonoInst *)ins->inst_p0;
13945
13946                                 if (var->opcode == OP_VTARG_ADDR) {
13947                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13948                                         MonoInst *vtaddr = var->inst_left;
13949                                         if (vtaddr->opcode == OP_REGVAR) {
13950                                                 ins->opcode = OP_MOVE;
13951                                                 ins->sreg1 = vtaddr->dreg;
13952                                         }
13953                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13954                                                 ins->opcode = OP_LOAD_MEMBASE;
13955                                                 ins->inst_basereg = vtaddr->inst_basereg;
13956                                                 ins->inst_offset = vtaddr->inst_offset;
13957                                         } else
13958                                                 NOT_IMPLEMENTED;
13959                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
13960                                         /* gsharedvt arg passed by ref */
13961                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13962
13963                                         ins->opcode = OP_LOAD_MEMBASE;
13964                                         ins->inst_basereg = var->inst_basereg;
13965                                         ins->inst_offset = var->inst_offset;
13966                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
13967                                         MonoInst *load, *load2, *load3;
13968                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
13969                                         int reg1, reg2, reg3;
13970                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13971                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13972
13973                                         /*
13974                                          * gsharedvt local.
13975                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13976                                          */
13977
13978                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13979
13980                                         g_assert (info_var);
13981                                         g_assert (locals_var);
13982
13983                                         /* Mark the instruction used to compute the locals var as used */
13984                                         cfg->gsharedvt_locals_var_ins = NULL;
13985
13986                                         /* Load the offset */
13987                                         if (info_var->opcode == OP_REGOFFSET) {
13988                                                 reg1 = alloc_ireg (cfg);
13989                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13990                                         } else if (info_var->opcode == OP_REGVAR) {
13991                                                 load = NULL;
13992                                                 reg1 = info_var->dreg;
13993                                         } else {
13994                                                 g_assert_not_reached ();
13995                                         }
13996                                         reg2 = alloc_ireg (cfg);
13997                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13998                                         /* Load the locals area address */
13999                                         reg3 = alloc_ireg (cfg);
14000                                         if (locals_var->opcode == OP_REGOFFSET) {
14001                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14002                                         } else if (locals_var->opcode == OP_REGVAR) {
14003                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14004                                         } else {
14005                                                 g_assert_not_reached ();
14006                                         }
14007                                         /* Compute the address */
14008                                         ins->opcode = OP_PADD;
14009                                         ins->sreg1 = reg3;
14010                                         ins->sreg2 = reg2;
14011
14012                                         mono_bblock_insert_before_ins (bb, ins, load3);
14013                                         mono_bblock_insert_before_ins (bb, load3, load2);
14014                                         if (load)
14015                                                 mono_bblock_insert_before_ins (bb, load2, load);
14016                                 } else {
14017                                         g_assert (var->opcode == OP_REGOFFSET);
14018
14019                                         ins->opcode = OP_ADD_IMM;
14020                                         ins->sreg1 = var->inst_basereg;
14021                                         ins->inst_imm = var->inst_offset;
14022                                 }
14023
14024                                 *need_local_opts = TRUE;
14025                                 spec = INS_INFO (ins->opcode);
14026                         }
14027
14028                         if (ins->opcode < MONO_CEE_LAST) {
14029                                 mono_print_ins (ins);
14030                                 g_assert_not_reached ();
14031                         }
14032
14033                         /*
14034                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14035                          * src register.
14036                          * FIXME:
14037                          */
14038                         if (MONO_IS_STORE_MEMBASE (ins)) {
14039                                 tmp_reg = ins->dreg;
14040                                 ins->dreg = ins->sreg2;
14041                                 ins->sreg2 = tmp_reg;
14042                                 store = TRUE;
14043
14044                                 spec2 [MONO_INST_DEST] = ' ';
14045                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14046                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14047                                 spec2 [MONO_INST_SRC3] = ' ';
14048                                 spec = spec2;
14049                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14050                                 g_assert_not_reached ();
14051                         else
14052                                 store = FALSE;
14053                         no_lvreg = FALSE;
14054
14055                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14056                                 printf ("\t %.3s %d", spec, ins->dreg);
14057                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14058                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14059                                         printf (" %d", sregs [srcindex]);
14060                                 printf ("\n");
14061                         }
14062
14063                         /***************/
14064                         /*    DREG     */
14065                         /***************/
14066                         regtype = spec [MONO_INST_DEST];
14067                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14068                         prev_dreg = -1;
14069
14070                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14071                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14072                                 MonoInst *store_ins;
14073                                 int store_opcode;
14074                                 MonoInst *def_ins = ins;
14075                                 int dreg = ins->dreg; /* The original vreg */
14076
14077                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14078
14079                                 if (var->opcode == OP_REGVAR) {
14080                                         ins->dreg = var->dreg;
14081                                 } 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)) {
14082                                         /* 
14083                                          * Instead of emitting a load+store, use a _membase opcode.
14084                                          */
14085                                         g_assert (var->opcode == OP_REGOFFSET);
14086                                         if (ins->opcode == OP_MOVE) {
14087                                                 NULLIFY_INS (ins);
14088                                                 def_ins = NULL;
14089                                         } else {
14090                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14091                                                 ins->inst_basereg = var->inst_basereg;
14092                                                 ins->inst_offset = var->inst_offset;
14093                                                 ins->dreg = -1;
14094                                         }
14095                                         spec = INS_INFO (ins->opcode);
14096                                 } else {
14097                                         guint32 lvreg;
14098
14099                                         g_assert (var->opcode == OP_REGOFFSET);
14100
14101                                         prev_dreg = ins->dreg;
14102
14103                                         /* Invalidate any previous lvreg for this vreg */
14104                                         vreg_to_lvreg [ins->dreg] = 0;
14105
14106                                         lvreg = 0;
14107
14108                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14109                                                 regtype = 'l';
14110                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14111                                         }
14112
14113                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14114
14115 #if SIZEOF_REGISTER != 8
14116                                         if (regtype == 'l') {
14117                                                 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));
14118                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14119                                                 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));
14120                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14121                                                 def_ins = store_ins;
14122                                         }
14123                                         else
14124 #endif
14125                                         {
14126                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14127
14128                                                 /* Try to fuse the store into the instruction itself */
14129                                                 /* FIXME: Add more instructions */
14130                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14131                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14132                                                         ins->inst_imm = ins->inst_c0;
14133                                                         ins->inst_destbasereg = var->inst_basereg;
14134                                                         ins->inst_offset = var->inst_offset;
14135                                                         spec = INS_INFO (ins->opcode);
14136                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14137                                                         ins->opcode = store_opcode;
14138                                                         ins->inst_destbasereg = var->inst_basereg;
14139                                                         ins->inst_offset = var->inst_offset;
14140
14141                                                         no_lvreg = TRUE;
14142
14143                                                         tmp_reg = ins->dreg;
14144                                                         ins->dreg = ins->sreg2;
14145                                                         ins->sreg2 = tmp_reg;
14146                                                         store = TRUE;
14147
14148                                                         spec2 [MONO_INST_DEST] = ' ';
14149                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14150                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14151                                                         spec2 [MONO_INST_SRC3] = ' ';
14152                                                         spec = spec2;
14153                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14154                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14155                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14156                                                         ins->dreg = -1;
14157                                                         ins->inst_basereg = var->inst_basereg;
14158                                                         ins->inst_offset = var->inst_offset;
14159                                                         spec = INS_INFO (ins->opcode);
14160                                                 } else {
14161                                                         /* printf ("INS: "); mono_print_ins (ins); */
14162                                                         /* Create a store instruction */
14163                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14164
14165                                                         /* Insert it after the instruction */
14166                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14167
14168                                                         def_ins = store_ins;
14169
14170                                                         /* 
14171                                                          * We can't assign ins->dreg to var->dreg here, since the
14172                                                          * sregs could use it. So set a flag, and do it after
14173                                                          * the sregs.
14174                                                          */
14175                                                         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)))
14176                                                                 dest_has_lvreg = TRUE;
14177                                                 }
14178                                         }
14179                                 }
14180
14181                                 if (def_ins && !live_range_start [dreg]) {
14182                                         live_range_start [dreg] = def_ins;
14183                                         live_range_start_bb [dreg] = bb;
14184                                 }
14185
14186                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14187                                         MonoInst *tmp;
14188
14189                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14190                                         tmp->inst_c1 = dreg;
14191                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14192                                 }
14193                         }
14194
14195                         /************/
14196                         /*  SREGS   */
14197                         /************/
14198                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14199                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14200                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14201                                 sreg = sregs [srcindex];
14202
14203                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14204                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14205                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14206                                         MonoInst *use_ins = ins;
14207                                         MonoInst *load_ins;
14208                                         guint32 load_opcode;
14209
14210                                         if (var->opcode == OP_REGVAR) {
14211                                                 sregs [srcindex] = var->dreg;
14212                                                 //mono_inst_set_src_registers (ins, sregs);
14213                                                 live_range_end [sreg] = use_ins;
14214                                                 live_range_end_bb [sreg] = bb;
14215
14216                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14217                                                         MonoInst *tmp;
14218
14219                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14220                                                         /* var->dreg is a hreg */
14221                                                         tmp->inst_c1 = sreg;
14222                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14223                                                 }
14224
14225                                                 continue;
14226                                         }
14227
14228                                         g_assert (var->opcode == OP_REGOFFSET);
14229                                                 
14230                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14231
14232                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14233
14234                                         if (vreg_to_lvreg [sreg]) {
14235                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14236
14237                                                 /* The variable is already loaded to an lvreg */
14238                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14239                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14240                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14241                                                 //mono_inst_set_src_registers (ins, sregs);
14242                                                 continue;
14243                                         }
14244
14245                                         /* Try to fuse the load into the instruction */
14246                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14247                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14248                                                 sregs [0] = var->inst_basereg;
14249                                                 //mono_inst_set_src_registers (ins, sregs);
14250                                                 ins->inst_offset = var->inst_offset;
14251                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14252                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14253                                                 sregs [1] = var->inst_basereg;
14254                                                 //mono_inst_set_src_registers (ins, sregs);
14255                                                 ins->inst_offset = var->inst_offset;
14256                                         } else {
14257                                                 if (MONO_IS_REAL_MOVE (ins)) {
14258                                                         ins->opcode = OP_NOP;
14259                                                         sreg = ins->dreg;
14260                                                 } else {
14261                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14262
14263                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14264
14265                                                         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) {
14266                                                                 if (var->dreg == prev_dreg) {
14267                                                                         /*
14268                                                                          * sreg refers to the value loaded by the load
14269                                                                          * emitted below, but we need to use ins->dreg
14270                                                                          * since it refers to the store emitted earlier.
14271                                                                          */
14272                                                                         sreg = ins->dreg;
14273                                                                 }
14274                                                                 g_assert (sreg != -1);
14275                                                                 vreg_to_lvreg [var->dreg] = sreg;
14276                                                                 if (lvregs_len >= lvregs_size) {
14277                                                                         guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
14278                                                                         memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
14279                                                                         lvregs = new_lvregs;
14280                                                                         lvregs_size *= 2;
14281                                                                 }
14282                                                                 lvregs [lvregs_len ++] = var->dreg;
14283                                                         }
14284                                                 }
14285
14286                                                 sregs [srcindex] = sreg;
14287                                                 //mono_inst_set_src_registers (ins, sregs);
14288
14289 #if SIZEOF_REGISTER != 8
14290                                                 if (regtype == 'l') {
14291                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14292                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14293                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14294                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14295                                                         use_ins = load_ins;
14296                                                 }
14297                                                 else
14298 #endif
14299                                                 {
14300 #if SIZEOF_REGISTER == 4
14301                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14302 #endif
14303                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14304                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14305                                                         use_ins = load_ins;
14306                                                 }
14307                                         }
14308
14309                                         if (var->dreg < orig_next_vreg) {
14310                                                 live_range_end [var->dreg] = use_ins;
14311                                                 live_range_end_bb [var->dreg] = bb;
14312                                         }
14313
14314                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14315                                                 MonoInst *tmp;
14316
14317                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14318                                                 tmp->inst_c1 = var->dreg;
14319                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14320                                         }
14321                                 }
14322                         }
14323                         mono_inst_set_src_registers (ins, sregs);
14324
14325                         if (dest_has_lvreg) {
14326                                 g_assert (ins->dreg != -1);
14327                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14328                                 if (lvregs_len >= lvregs_size) {
14329                                         guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
14330                                         memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
14331                                         lvregs = new_lvregs;
14332                                         lvregs_size *= 2;
14333                                 }
14334                                 lvregs [lvregs_len ++] = prev_dreg;
14335                                 dest_has_lvreg = FALSE;
14336                         }
14337
14338                         if (store) {
14339                                 tmp_reg = ins->dreg;
14340                                 ins->dreg = ins->sreg2;
14341                                 ins->sreg2 = tmp_reg;
14342                         }
14343
14344                         if (MONO_IS_CALL (ins)) {
14345                                 /* Clear vreg_to_lvreg array */
14346                                 for (i = 0; i < lvregs_len; i++)
14347                                         vreg_to_lvreg [lvregs [i]] = 0;
14348                                 lvregs_len = 0;
14349                         } else if (ins->opcode == OP_NOP) {
14350                                 ins->dreg = -1;
14351                                 MONO_INST_NULLIFY_SREGS (ins);
14352                         }
14353
14354                         if (cfg->verbose_level > 2)
14355                                 mono_print_ins_index (1, ins);
14356                 }
14357
14358                 /* Extend the live range based on the liveness info */
14359                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14360                         for (i = 0; i < cfg->num_varinfo; i ++) {
14361                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14362
14363                                 if (vreg_is_volatile (cfg, vi->vreg))
14364                                         /* The liveness info is incomplete */
14365                                         continue;
14366
14367                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14368                                         /* Live from at least the first ins of this bb */
14369                                         live_range_start [vi->vreg] = bb->code;
14370                                         live_range_start_bb [vi->vreg] = bb;
14371                                 }
14372
14373                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14374                                         /* Live at least until the last ins of this bb */
14375                                         live_range_end [vi->vreg] = bb->last_ins;
14376                                         live_range_end_bb [vi->vreg] = bb;
14377                                 }
14378                         }
14379                 }
14380         }
14381         
14382         /*
14383          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14384          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14385          */
14386         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14387                 for (i = 0; i < cfg->num_varinfo; ++i) {
14388                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14389                         MonoInst *ins;
14390
14391                         if (live_range_start [vreg]) {
14392                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14393                                 ins->inst_c0 = i;
14394                                 ins->inst_c1 = vreg;
14395                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14396                         }
14397                         if (live_range_end [vreg]) {
14398                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14399                                 ins->inst_c0 = i;
14400                                 ins->inst_c1 = vreg;
14401                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14402                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14403                                 else
14404                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14405                         }
14406                 }
14407         }
14408
14409         if (cfg->gsharedvt_locals_var_ins) {
14410                 /* Nullify if unused */
14411                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14412                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14413         }
14414
14415         g_free (live_range_start);
14416         g_free (live_range_end);
14417         g_free (live_range_start_bb);
14418         g_free (live_range_end_bb);
14419 }
14420
14421
14422 /**
14423  * FIXME:
14424  * - use 'iadd' instead of 'int_add'
14425  * - handling ovf opcodes: decompose in method_to_ir.
14426  * - unify iregs/fregs
14427  *   -> partly done, the missing parts are:
14428  *   - a more complete unification would involve unifying the hregs as well, so
14429  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14430  *     would no longer map to the machine hregs, so the code generators would need to
14431  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14432  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14433  *     fp/non-fp branches speeds it up by about 15%.
14434  * - use sext/zext opcodes instead of shifts
14435  * - add OP_ICALL
14436  * - get rid of TEMPLOADs if possible and use vregs instead
14437  * - clean up usage of OP_P/OP_ opcodes
14438  * - cleanup usage of DUMMY_USE
14439  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14440  *   stack
14441  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14442  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14443  * - make sure handle_stack_args () is called before the branch is emitted
14444  * - when the new IR is done, get rid of all unused stuff
14445  * - COMPARE/BEQ as separate instructions or unify them ?
14446  *   - keeping them separate allows specialized compare instructions like
14447  *     compare_imm, compare_membase
14448  *   - most back ends unify fp compare+branch, fp compare+ceq
14449  * - integrate mono_save_args into inline_method
14450  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14451  * - handle long shift opts on 32 bit platforms somehow: they require 
14452  *   3 sregs (2 for arg1 and 1 for arg2)
14453  * - make byref a 'normal' type.
14454  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14455  *   variable if needed.
14456  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14457  *   like inline_method.
14458  * - remove inlining restrictions
14459  * - fix LNEG and enable cfold of INEG
14460  * - generalize x86 optimizations like ldelema as a peephole optimization
14461  * - add store_mem_imm for amd64
14462  * - optimize the loading of the interruption flag in the managed->native wrappers
14463  * - avoid special handling of OP_NOP in passes
14464  * - move code inserting instructions into one function/macro.
14465  * - try a coalescing phase after liveness analysis
14466  * - add float -> vreg conversion + local optimizations on !x86
14467  * - figure out how to handle decomposed branches during optimizations, ie.
14468  *   compare+branch, op_jump_table+op_br etc.
14469  * - promote RuntimeXHandles to vregs
14470  * - vtype cleanups:
14471  *   - add a NEW_VARLOADA_VREG macro
14472  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14473  *   accessing vtype fields.
14474  * - get rid of I8CONST on 64 bit platforms
14475  * - dealing with the increase in code size due to branches created during opcode
14476  *   decomposition:
14477  *   - use extended basic blocks
14478  *     - all parts of the JIT
14479  *     - handle_global_vregs () && local regalloc
14480  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14481  * - sources of increase in code size:
14482  *   - vtypes
14483  *   - long compares
14484  *   - isinst and castclass
14485  *   - lvregs not allocated to global registers even if used multiple times
14486  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14487  *   meaningful.
14488  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14489  * - add all micro optimizations from the old JIT
14490  * - put tree optimizations into the deadce pass
14491  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14492  *   specific function.
14493  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14494  *   fcompare + branchCC.
14495  * - create a helper function for allocating a stack slot, taking into account 
14496  *   MONO_CFG_HAS_SPILLUP.
14497  * - merge r68207.
14498  * - merge the ia64 switch changes.
14499  * - optimize mono_regstate2_alloc_int/float.
14500  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14501  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14502  *   parts of the tree could be separated by other instructions, killing the tree
14503  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14504  *   instructions if the result of the load is used multiple times ?
14505  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14506  * - LAST MERGE: 108395.
14507  * - when returning vtypes in registers, generate IR and append it to the end of the
14508  *   last bb instead of doing it in the epilog.
14509  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14510  */
14511
14512 /*
14513
14514 NOTES
14515 -----
14516
14517 - When to decompose opcodes:
14518   - earlier: this makes some optimizations hard to implement, since the low level IR
14519   no longer contains the neccessary information. But it is easier to do.
14520   - later: harder to implement, enables more optimizations.
14521 - Branches inside bblocks:
14522   - created when decomposing complex opcodes. 
14523     - branches to another bblock: harmless, but not tracked by the branch 
14524       optimizations, so need to branch to a label at the start of the bblock.
14525     - branches to inside the same bblock: very problematic, trips up the local
14526       reg allocator. Can be fixed by spitting the current bblock, but that is a
14527       complex operation, since some local vregs can become global vregs etc.
14528 - Local/global vregs:
14529   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14530     local register allocator.
14531   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14532     structure, created by mono_create_var (). Assigned to hregs or the stack by
14533     the global register allocator.
14534 - When to do optimizations like alu->alu_imm:
14535   - earlier -> saves work later on since the IR will be smaller/simpler
14536   - later -> can work on more instructions
14537 - Handling of valuetypes:
14538   - When a vtype is pushed on the stack, a new temporary is created, an 
14539     instruction computing its address (LDADDR) is emitted and pushed on
14540     the stack. Need to optimize cases when the vtype is used immediately as in
14541     argument passing, stloc etc.
14542 - Instead of the to_end stuff in the old JIT, simply call the function handling
14543   the values on the stack before emitting the last instruction of the bb.
14544 */
14545
14546 #else /* !DISABLE_JIT */
14547
14548 void
14549 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
14550 {
14551 }
14552
14553 #endif /* !DISABLE_JIT */