[jit] Fix a regression introduced by the addition of an assert in bf467001b10a0e4fe38...
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12  */
13
14 #include <config.h>
15 #include <mono/utils/mono-compiler.h>
16
17 #ifndef DISABLE_JIT
18
19 #include <signal.h>
20
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24
25 #include <math.h>
26 #include <string.h>
27 #include <ctype.h>
28
29 #ifdef HAVE_SYS_TIME_H
30 #include <sys/time.h>
31 #endif
32
33 #ifdef HAVE_ALLOCA_H
34 #include <alloca.h>
35 #endif
36
37 #include <mono/utils/memcheck.h>
38 #include "mini.h"
39 #include <mono/metadata/abi-details.h>
40 #include <mono/metadata/assembly.h>
41 #include <mono/metadata/attrdefs.h>
42 #include <mono/metadata/loader.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/class.h>
45 #include <mono/metadata/object.h>
46 #include <mono/metadata/exception.h>
47 #include <mono/metadata/opcodes.h>
48 #include <mono/metadata/mono-endian.h>
49 #include <mono/metadata/tokentype.h>
50 #include <mono/metadata/tabledefs.h>
51 #include <mono/metadata/marshal.h>
52 #include <mono/metadata/debug-helpers.h>
53 #include <mono/metadata/mono-debug.h>
54 #include <mono/metadata/mono-debug-debugger.h>
55 #include <mono/metadata/gc-internals.h>
56 #include <mono/metadata/security-manager.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/security-core-clr.h>
59 #include <mono/metadata/profiler-private.h>
60 #include <mono/metadata/profiler.h>
61 #include <mono/metadata/monitor.h>
62 #include <mono/metadata/debug-mono-symfile.h>
63 #include <mono/utils/mono-compiler.h>
64 #include <mono/utils/mono-memory-model.h>
65 #include <mono/utils/mono-error-internals.h>
66 #include <mono/metadata/mono-basic-block.h>
67 #include <mono/metadata/reflection-internals.h>
68 #include <mono/utils/mono-threads-coop.h>
69
70 #include "trace.h"
71
72 #include "ir-emit.h"
73
74 #include "jit-icalls.h"
75 #include "jit.h"
76 #include "debugger-agent.h"
77 #include "seq-points.h"
78 #include "aot-compiler.h"
79 #include "mini-llvm.h"
80
81 #define BRANCH_COST 10
82 #define INLINE_LENGTH_LIMIT 20
83
84 /* These have 'cfg' as an implicit argument */
85 #define INLINE_FAILURE(msg) do {                                                                        \
86         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
87                 inline_failure (cfg, msg);                                                                              \
88                 goto exception_exit;                                                                                    \
89         } \
90         } while (0)
91 #define CHECK_CFG_EXCEPTION do {\
92                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
93                         goto exception_exit;                                            \
94         } while (0)
95 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
96                 field_access_failure ((cfg), (method), (field));                        \
97                 goto exception_exit;    \
98         } while (0)
99 #define GENERIC_SHARING_FAILURE(opcode) do {            \
100                 if (cfg->gshared) {                                                                     \
101                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
102                         goto exception_exit;    \
103                 }                       \
104         } while (0)
105 #define GSHAREDVT_FAILURE(opcode) do {          \
106         if (cfg->gsharedvt) {                                                                                           \
107                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
108                 goto exception_exit;                                                                                    \
109         }                                                                                                                                       \
110         } while (0)
111 #define OUT_OF_MEMORY_FAILURE do {      \
112                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
113                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
114                 goto exception_exit;    \
115         } while (0)
116 #define DISABLE_AOT(cfg) do { \
117                 if ((cfg)->verbose_level >= 2)                                            \
118                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
119                 (cfg)->disable_aot = TRUE;                                                        \
120         } while (0)
121 #define LOAD_ERROR do { \
122                 break_on_unverified ();                                                         \
123                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
124                 goto exception_exit;                                                                    \
125         } while (0)
126
127 #define TYPE_LOAD_ERROR(klass) do { \
128                 cfg->exception_ptr = klass; \
129                 LOAD_ERROR;                                     \
130         } while (0)
131
132 #define CHECK_CFG_ERROR do {\
133                 if (!mono_error_ok (&cfg->error)) { \
134                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
135                         goto mono_error_exit; \
136                 } \
137         } while (0)
138
139 /* Determine whenever 'ins' represents a load of the 'this' argument */
140 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
141
142 static int ldind_to_load_membase (int opcode);
143 static int stind_to_store_membase (int opcode);
144
145 int mono_op_to_op_imm (int opcode);
146 int mono_op_to_op_imm_noemul (int opcode);
147
148 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
149
150 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
151                                                   guchar *ip, guint real_offset, gboolean inline_always);
152 static MonoInst*
153 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
154
155 inline static MonoInst*
156 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg);
157
158 /* helper methods signatures */
159 static MonoMethodSignature *helper_sig_domain_get;
160 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
161 static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline;
162 static MonoMethodSignature *helper_sig_jit_thread_attach;
163 static MonoMethodSignature *helper_sig_get_tls_tramp;
164 static MonoMethodSignature *helper_sig_set_tls_tramp;
165
166 /* type loading helpers */
167 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
168 static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, System.Diagnostics, DebuggableAttribute)
169
170 /*
171  * Instruction metadata
172  */
173 #ifdef MINI_OP
174 #undef MINI_OP
175 #endif
176 #ifdef MINI_OP3
177 #undef MINI_OP3
178 #endif
179 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
180 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
181 #define NONE ' '
182 #define IREG 'i'
183 #define FREG 'f'
184 #define VREG 'v'
185 #define XREG 'x'
186 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
187 #define LREG IREG
188 #else
189 #define LREG 'l'
190 #endif
191 /* keep in sync with the enum in mini.h */
192 const char
193 ins_info[] = {
194 #include "mini-ops.h"
195 };
196 #undef MINI_OP
197 #undef MINI_OP3
198
199 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
200 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
201 /* 
202  * This should contain the index of the last sreg + 1. This is not the same
203  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
204  */
205 const gint8 ins_sreg_counts[] = {
206 #include "mini-ops.h"
207 };
208 #undef MINI_OP
209 #undef MINI_OP3
210
211 #define MONO_INIT_VARINFO(vi,id) do { \
212         (vi)->range.first_use.pos.bid = 0xffff; \
213         (vi)->reg = -1; \
214         (vi)->idx = (id); \
215 } while (0)
216
217 guint32
218 mono_alloc_ireg (MonoCompile *cfg)
219 {
220         return alloc_ireg (cfg);
221 }
222
223 guint32
224 mono_alloc_lreg (MonoCompile *cfg)
225 {
226         return alloc_lreg (cfg);
227 }
228
229 guint32
230 mono_alloc_freg (MonoCompile *cfg)
231 {
232         return alloc_freg (cfg);
233 }
234
235 guint32
236 mono_alloc_preg (MonoCompile *cfg)
237 {
238         return alloc_preg (cfg);
239 }
240
241 guint32
242 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
243 {
244         return alloc_dreg (cfg, stack_type);
245 }
246
247 /*
248  * mono_alloc_ireg_ref:
249  *
250  *   Allocate an IREG, and mark it as holding a GC ref.
251  */
252 guint32
253 mono_alloc_ireg_ref (MonoCompile *cfg)
254 {
255         return alloc_ireg_ref (cfg);
256 }
257
258 /*
259  * mono_alloc_ireg_mp:
260  *
261  *   Allocate an IREG, and mark it as holding a managed pointer.
262  */
263 guint32
264 mono_alloc_ireg_mp (MonoCompile *cfg)
265 {
266         return alloc_ireg_mp (cfg);
267 }
268
269 /*
270  * mono_alloc_ireg_copy:
271  *
272  *   Allocate an IREG with the same GC type as VREG.
273  */
274 guint32
275 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
276 {
277         if (vreg_is_ref (cfg, vreg))
278                 return alloc_ireg_ref (cfg);
279         else if (vreg_is_mp (cfg, vreg))
280                 return alloc_ireg_mp (cfg);
281         else
282                 return alloc_ireg (cfg);
283 }
284
285 guint
286 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
287 {
288         if (type->byref)
289                 return OP_MOVE;
290
291         type = mini_get_underlying_type (type);
292 handle_enum:
293         switch (type->type) {
294         case MONO_TYPE_I1:
295         case MONO_TYPE_U1:
296                 return OP_MOVE;
297         case MONO_TYPE_I2:
298         case MONO_TYPE_U2:
299                 return OP_MOVE;
300         case MONO_TYPE_I4:
301         case MONO_TYPE_U4:
302                 return OP_MOVE;
303         case MONO_TYPE_I:
304         case MONO_TYPE_U:
305         case MONO_TYPE_PTR:
306         case MONO_TYPE_FNPTR:
307                 return OP_MOVE;
308         case MONO_TYPE_CLASS:
309         case MONO_TYPE_STRING:
310         case MONO_TYPE_OBJECT:
311         case MONO_TYPE_SZARRAY:
312         case MONO_TYPE_ARRAY:    
313                 return OP_MOVE;
314         case MONO_TYPE_I8:
315         case MONO_TYPE_U8:
316 #if SIZEOF_REGISTER == 8
317                 return OP_MOVE;
318 #else
319                 return OP_LMOVE;
320 #endif
321         case MONO_TYPE_R4:
322                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
323         case MONO_TYPE_R8:
324                 return OP_FMOVE;
325         case MONO_TYPE_VALUETYPE:
326                 if (type->data.klass->enumtype) {
327                         type = mono_class_enum_basetype (type->data.klass);
328                         goto handle_enum;
329                 }
330                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
331                         return OP_XMOVE;
332                 return OP_VMOVE;
333         case MONO_TYPE_TYPEDBYREF:
334                 return OP_VMOVE;
335         case MONO_TYPE_GENERICINST:
336                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
337                         return OP_XMOVE;
338                 type = &type->data.generic_class->container_class->byval_arg;
339                 goto handle_enum;
340         case MONO_TYPE_VAR:
341         case MONO_TYPE_MVAR:
342                 g_assert (cfg->gshared);
343                 if (mini_type_var_is_vt (type))
344                         return OP_VMOVE;
345                 else
346                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
347         default:
348                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
349         }
350         return -1;
351 }
352
353 void
354 mono_print_bb (MonoBasicBlock *bb, const char *msg)
355 {
356         int i;
357         MonoInst *tree;
358
359         printf ("\n%s %d: [IN: ", msg, bb->block_num);
360         for (i = 0; i < bb->in_count; ++i)
361                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
362         printf (", OUT: ");
363         for (i = 0; i < bb->out_count; ++i)
364                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
365         printf (" ]\n");
366         for (tree = bb->code; tree; tree = tree->next)
367                 mono_print_ins_index (-1, tree);
368 }
369
370 void
371 mono_create_helper_signatures (void)
372 {
373         helper_sig_domain_get = mono_create_icall_signature ("ptr");
374         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
375         helper_sig_llvmonly_imt_trampoline = mono_create_icall_signature ("ptr ptr ptr");
376         helper_sig_jit_thread_attach = mono_create_icall_signature ("ptr ptr");
377         helper_sig_get_tls_tramp = mono_create_icall_signature ("ptr");
378         helper_sig_set_tls_tramp = mono_create_icall_signature ("void ptr");
379 }
380
381 static MONO_NEVER_INLINE void
382 break_on_unverified (void)
383 {
384         if (mini_get_debug_options ()->break_on_unverified)
385                 G_BREAKPOINT ();
386 }
387
388 static MONO_NEVER_INLINE void
389 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
390 {
391         char *method_fname = mono_method_full_name (method, TRUE);
392         char *field_fname = mono_field_full_name (field);
393         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
394         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
395         g_free (method_fname);
396         g_free (field_fname);
397 }
398
399 static MONO_NEVER_INLINE void
400 inline_failure (MonoCompile *cfg, const char *msg)
401 {
402         if (cfg->verbose_level >= 2)
403                 printf ("inline failed: %s\n", msg);
404         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
405 }
406
407 static MONO_NEVER_INLINE void
408 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
409 {
410         if (cfg->verbose_level > 2)                                                                                     \
411                 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);
412         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
413 }
414
415 static MONO_NEVER_INLINE void
416 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
417 {
418         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);
419         if (cfg->verbose_level >= 2)
420                 printf ("%s\n", cfg->exception_message);
421         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
422 }
423
424 /*
425  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
426  * foo<T> (int i) { ldarg.0; box T; }
427  */
428 #define UNVERIFIED do { \
429         if (cfg->gsharedvt) { \
430                 if (cfg->verbose_level > 2)                                                                     \
431                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
432                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
433                 goto exception_exit;                                                                                    \
434         }                                                                                                                                       \
435         break_on_unverified ();                                                                                         \
436         goto unverified;                                                                                                        \
437 } while (0)
438
439 #define GET_BBLOCK(cfg,tblock,ip) do {  \
440                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
441                 if (!(tblock)) {        \
442                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
443             NEW_BBLOCK (cfg, (tblock)); \
444                         (tblock)->cil_code = (ip);      \
445                         ADD_BBLOCK (cfg, (tblock));     \
446                 } \
447         } while (0)
448
449 #if defined(TARGET_X86) || defined(TARGET_AMD64)
450 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
451                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
452                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
453                 (dest)->sreg1 = (sr1); \
454                 (dest)->sreg2 = (sr2); \
455                 (dest)->inst_imm = (imm); \
456                 (dest)->backend.shift_amount = (shift); \
457                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
458         } while (0)
459 #endif
460
461 /* Emit conversions so both operands of a binary opcode are of the same type */
462 static void
463 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
464 {
465         MonoInst *arg1 = *arg1_ref;
466         MonoInst *arg2 = *arg2_ref;
467
468         if (cfg->r4fp &&
469                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
470                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
471                 MonoInst *conv;
472
473                 /* Mixing r4/r8 is allowed by the spec */
474                 if (arg1->type == STACK_R4) {
475                         int dreg = alloc_freg (cfg);
476
477                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
478                         conv->type = STACK_R8;
479                         ins->sreg1 = dreg;
480                         *arg1_ref = conv;
481                 }
482                 if (arg2->type == STACK_R4) {
483                         int dreg = alloc_freg (cfg);
484
485                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
486                         conv->type = STACK_R8;
487                         ins->sreg2 = dreg;
488                         *arg2_ref = conv;
489                 }
490         }
491
492 #if SIZEOF_REGISTER == 8
493         /* FIXME: Need to add many more cases */
494         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
495                 MonoInst *widen;
496
497                 int dr = alloc_preg (cfg);
498                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
499                 (ins)->sreg2 = widen->dreg;
500         }
501 #endif
502 }
503
504 #define ADD_BINOP(op) do {      \
505                 MONO_INST_NEW (cfg, ins, (op)); \
506                 sp -= 2;        \
507                 ins->sreg1 = sp [0]->dreg;      \
508                 ins->sreg2 = sp [1]->dreg;      \
509                 type_from_op (cfg, ins, sp [0], sp [1]);        \
510                 CHECK_TYPE (ins);       \
511                 /* Have to insert a widening op */               \
512         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
513         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
514         MONO_ADD_INS ((cfg)->cbb, (ins)); \
515         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
516         } while (0)
517
518 #define ADD_UNOP(op) do {       \
519                 MONO_INST_NEW (cfg, ins, (op)); \
520                 sp--;   \
521                 ins->sreg1 = sp [0]->dreg;      \
522                 type_from_op (cfg, ins, sp [0], NULL);  \
523                 CHECK_TYPE (ins);       \
524         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
525         MONO_ADD_INS ((cfg)->cbb, (ins)); \
526                 *sp++ = mono_decompose_opcode (cfg, ins);       \
527         } while (0)
528
529 #define ADD_BINCOND(next_block) do {    \
530                 MonoInst *cmp;  \
531                 sp -= 2; \
532                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
533                 cmp->sreg1 = sp [0]->dreg;      \
534                 cmp->sreg2 = sp [1]->dreg;      \
535                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
536                 CHECK_TYPE (cmp);       \
537                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
538                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
539                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
540                 GET_BBLOCK (cfg, tblock, target);               \
541                 link_bblock (cfg, cfg->cbb, tblock);    \
542                 ins->inst_true_bb = tblock;     \
543                 if ((next_block)) {     \
544                         link_bblock (cfg, cfg->cbb, (next_block));      \
545                         ins->inst_false_bb = (next_block);      \
546                         start_new_bblock = 1;   \
547                 } else {        \
548                         GET_BBLOCK (cfg, tblock, ip);           \
549                         link_bblock (cfg, cfg->cbb, tblock);    \
550                         ins->inst_false_bb = tblock;    \
551                         start_new_bblock = 2;   \
552                 }       \
553                 if (sp != stack_start) {                                                                        \
554                     handle_stack_args (cfg, stack_start, sp - stack_start); \
555                         CHECK_UNVERIFIABLE (cfg); \
556                 } \
557         MONO_ADD_INS (cfg->cbb, cmp); \
558                 MONO_ADD_INS (cfg->cbb, ins);   \
559         } while (0)
560
561 /* *
562  * link_bblock: Links two basic blocks
563  *
564  * links two basic blocks in the control flow graph, the 'from'
565  * argument is the starting block and the 'to' argument is the block
566  * the control flow ends to after 'from'.
567  */
568 static void
569 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
570 {
571         MonoBasicBlock **newa;
572         int i, found;
573
574 #if 0
575         if (from->cil_code) {
576                 if (to->cil_code)
577                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
578                 else
579                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
580         } else {
581                 if (to->cil_code)
582                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
583                 else
584                         printf ("edge from entry to exit\n");
585         }
586 #endif
587
588         found = FALSE;
589         for (i = 0; i < from->out_count; ++i) {
590                 if (to == from->out_bb [i]) {
591                         found = TRUE;
592                         break;
593                 }
594         }
595         if (!found) {
596                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
597                 for (i = 0; i < from->out_count; ++i) {
598                         newa [i] = from->out_bb [i];
599                 }
600                 newa [i] = to;
601                 from->out_count++;
602                 from->out_bb = newa;
603         }
604
605         found = FALSE;
606         for (i = 0; i < to->in_count; ++i) {
607                 if (from == to->in_bb [i]) {
608                         found = TRUE;
609                         break;
610                 }
611         }
612         if (!found) {
613                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
614                 for (i = 0; i < to->in_count; ++i) {
615                         newa [i] = to->in_bb [i];
616                 }
617                 newa [i] = from;
618                 to->in_count++;
619                 to->in_bb = newa;
620         }
621 }
622
623 void
624 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
625 {
626         link_bblock (cfg, from, to);
627 }
628
629 /**
630  * mono_find_block_region:
631  *
632  *   We mark each basic block with a region ID. We use that to avoid BB
633  *   optimizations when blocks are in different regions.
634  *
635  * Returns:
636  *   A region token that encodes where this region is, and information
637  *   about the clause owner for this block.
638  *
639  *   The region encodes the try/catch/filter clause that owns this block
640  *   as well as the type.  -1 is a special value that represents a block
641  *   that is in none of try/catch/filter.
642  */
643 static int
644 mono_find_block_region (MonoCompile *cfg, int offset)
645 {
646         MonoMethodHeader *header = cfg->header;
647         MonoExceptionClause *clause;
648         int i;
649
650         for (i = 0; i < header->num_clauses; ++i) {
651                 clause = &header->clauses [i];
652                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
653                     (offset < (clause->handler_offset)))
654                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
655                            
656                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
657                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
658                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
659                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
660                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
661                         else
662                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
663                 }
664         }
665         for (i = 0; i < header->num_clauses; ++i) {
666                 clause = &header->clauses [i];
667
668                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
669                         return ((i + 1) << 8) | clause->flags;
670         }
671
672         return -1;
673 }
674
675 static gboolean
676 ip_in_finally_clause (MonoCompile *cfg, int offset)
677 {
678         MonoMethodHeader *header = cfg->header;
679         MonoExceptionClause *clause;
680         int i;
681
682         for (i = 0; i < header->num_clauses; ++i) {
683                 clause = &header->clauses [i];
684                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
685                         continue;
686
687                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
688                         return TRUE;
689         }
690         return FALSE;
691 }
692
693 static GList*
694 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
695 {
696         MonoMethodHeader *header = cfg->header;
697         MonoExceptionClause *clause;
698         int i;
699         GList *res = NULL;
700
701         for (i = 0; i < header->num_clauses; ++i) {
702                 clause = &header->clauses [i];
703                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
704                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
705                         if (clause->flags == type)
706                                 res = g_list_append (res, clause);
707                 }
708         }
709         return res;
710 }
711
712 static void
713 mono_create_spvar_for_region (MonoCompile *cfg, int region)
714 {
715         MonoInst *var;
716
717         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
718         if (var)
719                 return;
720
721         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
722         /* prevent it from being register allocated */
723         var->flags |= MONO_INST_VOLATILE;
724
725         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
726 }
727
728 MonoInst *
729 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
730 {
731         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
732 }
733
734 static MonoInst*
735 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
736 {
737         MonoInst *var;
738
739         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
740         if (var)
741                 return var;
742
743         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
744         /* prevent it from being register allocated */
745         var->flags |= MONO_INST_VOLATILE;
746
747         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
748
749         return var;
750 }
751
752 /*
753  * Returns the type used in the eval stack when @type is loaded.
754  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
755  */
756 void
757 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
758 {
759         MonoClass *klass;
760
761         type = mini_get_underlying_type (type);
762         inst->klass = klass = mono_class_from_mono_type (type);
763         if (type->byref) {
764                 inst->type = STACK_MP;
765                 return;
766         }
767
768 handle_enum:
769         switch (type->type) {
770         case MONO_TYPE_VOID:
771                 inst->type = STACK_INV;
772                 return;
773         case MONO_TYPE_I1:
774         case MONO_TYPE_U1:
775         case MONO_TYPE_I2:
776         case MONO_TYPE_U2:
777         case MONO_TYPE_I4:
778         case MONO_TYPE_U4:
779                 inst->type = STACK_I4;
780                 return;
781         case MONO_TYPE_I:
782         case MONO_TYPE_U:
783         case MONO_TYPE_PTR:
784         case MONO_TYPE_FNPTR:
785                 inst->type = STACK_PTR;
786                 return;
787         case MONO_TYPE_CLASS:
788         case MONO_TYPE_STRING:
789         case MONO_TYPE_OBJECT:
790         case MONO_TYPE_SZARRAY:
791         case MONO_TYPE_ARRAY:    
792                 inst->type = STACK_OBJ;
793                 return;
794         case MONO_TYPE_I8:
795         case MONO_TYPE_U8:
796                 inst->type = STACK_I8;
797                 return;
798         case MONO_TYPE_R4:
799                 inst->type = cfg->r4_stack_type;
800                 break;
801         case MONO_TYPE_R8:
802                 inst->type = STACK_R8;
803                 return;
804         case MONO_TYPE_VALUETYPE:
805                 if (type->data.klass->enumtype) {
806                         type = mono_class_enum_basetype (type->data.klass);
807                         goto handle_enum;
808                 } else {
809                         inst->klass = klass;
810                         inst->type = STACK_VTYPE;
811                         return;
812                 }
813         case MONO_TYPE_TYPEDBYREF:
814                 inst->klass = mono_defaults.typed_reference_class;
815                 inst->type = STACK_VTYPE;
816                 return;
817         case MONO_TYPE_GENERICINST:
818                 type = &type->data.generic_class->container_class->byval_arg;
819                 goto handle_enum;
820         case MONO_TYPE_VAR:
821         case MONO_TYPE_MVAR:
822                 g_assert (cfg->gshared);
823                 if (mini_is_gsharedvt_type (type)) {
824                         g_assert (cfg->gsharedvt);
825                         inst->type = STACK_VTYPE;
826                 } else {
827                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
828                 }
829                 return;
830         default:
831                 g_error ("unknown type 0x%02x in eval stack type", type->type);
832         }
833 }
834
835 /*
836  * The following tables are used to quickly validate the IL code in type_from_op ().
837  */
838 static const char
839 bin_num_table [STACK_MAX] [STACK_MAX] = {
840         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
841         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
842         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
843         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
844         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
845         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
846         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
847         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
848         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
849 };
850
851 static const char 
852 neg_table [] = {
853         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
854 };
855
856 /* reduce the size of this table */
857 static const char
858 bin_int_table [STACK_MAX] [STACK_MAX] = {
859         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
860         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
861         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
862         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
863         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
864         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
865         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
866         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
867 };
868
869 static const char
870 bin_comp_table [STACK_MAX] [STACK_MAX] = {
871 /*      Inv i  L  p  F  &  O  vt r4 */
872         {0},
873         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
874         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
875         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
876         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
877         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
878         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
879         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
880         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
881 };
882
883 /* reduce the size of this table */
884 static const char
885 shift_table [STACK_MAX] [STACK_MAX] = {
886         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
887         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
888         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
889         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
890         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
891         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
892         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
893         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
894 };
895
896 /*
897  * Tables to map from the non-specific opcode to the matching
898  * type-specific opcode.
899  */
900 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
901 static const guint16
902 binops_op_map [STACK_MAX] = {
903         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
904 };
905
906 /* handles from CEE_NEG to CEE_CONV_U8 */
907 static const guint16
908 unops_op_map [STACK_MAX] = {
909         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
910 };
911
912 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
913 static const guint16
914 ovfops_op_map [STACK_MAX] = {
915         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
916 };
917
918 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
919 static const guint16
920 ovf2ops_op_map [STACK_MAX] = {
921         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
922 };
923
924 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
925 static const guint16
926 ovf3ops_op_map [STACK_MAX] = {
927         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
928 };
929
930 /* handles from CEE_BEQ to CEE_BLT_UN */
931 static const guint16
932 beqops_op_map [STACK_MAX] = {
933         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
934 };
935
936 /* handles from CEE_CEQ to CEE_CLT_UN */
937 static const guint16
938 ceqops_op_map [STACK_MAX] = {
939         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
940 };
941
942 /*
943  * Sets ins->type (the type on the eval stack) according to the
944  * type of the opcode and the arguments to it.
945  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
946  *
947  * FIXME: this function sets ins->type unconditionally in some cases, but
948  * it should set it to invalid for some types (a conv.x on an object)
949  */
950 static void
951 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
952 {
953         switch (ins->opcode) {
954         /* binops */
955         case CEE_ADD:
956         case CEE_SUB:
957         case CEE_MUL:
958         case CEE_DIV:
959         case CEE_REM:
960                 /* FIXME: check unverifiable args for STACK_MP */
961                 ins->type = bin_num_table [src1->type] [src2->type];
962                 ins->opcode += binops_op_map [ins->type];
963                 break;
964         case CEE_DIV_UN:
965         case CEE_REM_UN:
966         case CEE_AND:
967         case CEE_OR:
968         case CEE_XOR:
969                 ins->type = bin_int_table [src1->type] [src2->type];
970                 ins->opcode += binops_op_map [ins->type];
971                 break;
972         case CEE_SHL:
973         case CEE_SHR:
974         case CEE_SHR_UN:
975                 ins->type = shift_table [src1->type] [src2->type];
976                 ins->opcode += binops_op_map [ins->type];
977                 break;
978         case OP_COMPARE:
979         case OP_LCOMPARE:
980         case OP_ICOMPARE:
981                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
982                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
983                         ins->opcode = OP_LCOMPARE;
984                 else if (src1->type == STACK_R4)
985                         ins->opcode = OP_RCOMPARE;
986                 else if (src1->type == STACK_R8)
987                         ins->opcode = OP_FCOMPARE;
988                 else
989                         ins->opcode = OP_ICOMPARE;
990                 break;
991         case OP_ICOMPARE_IMM:
992                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
993                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
994                         ins->opcode = OP_LCOMPARE_IMM;          
995                 break;
996         case CEE_BEQ:
997         case CEE_BGE:
998         case CEE_BGT:
999         case CEE_BLE:
1000         case CEE_BLT:
1001         case CEE_BNE_UN:
1002         case CEE_BGE_UN:
1003         case CEE_BGT_UN:
1004         case CEE_BLE_UN:
1005         case CEE_BLT_UN:
1006                 ins->opcode += beqops_op_map [src1->type];
1007                 break;
1008         case OP_CEQ:
1009                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
1010                 ins->opcode += ceqops_op_map [src1->type];
1011                 break;
1012         case OP_CGT:
1013         case OP_CGT_UN:
1014         case OP_CLT:
1015         case OP_CLT_UN:
1016                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
1017                 ins->opcode += ceqops_op_map [src1->type];
1018                 break;
1019         /* unops */
1020         case CEE_NEG:
1021                 ins->type = neg_table [src1->type];
1022                 ins->opcode += unops_op_map [ins->type];
1023                 break;
1024         case CEE_NOT:
1025                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1026                         ins->type = src1->type;
1027                 else
1028                         ins->type = STACK_INV;
1029                 ins->opcode += unops_op_map [ins->type];
1030                 break;
1031         case CEE_CONV_I1:
1032         case CEE_CONV_I2:
1033         case CEE_CONV_I4:
1034         case CEE_CONV_U4:
1035                 ins->type = STACK_I4;
1036                 ins->opcode += unops_op_map [src1->type];
1037                 break;
1038         case CEE_CONV_R_UN:
1039                 ins->type = STACK_R8;
1040                 switch (src1->type) {
1041                 case STACK_I4:
1042                 case STACK_PTR:
1043                         ins->opcode = OP_ICONV_TO_R_UN;
1044                         break;
1045                 case STACK_I8:
1046                         ins->opcode = OP_LCONV_TO_R_UN; 
1047                         break;
1048                 }
1049                 break;
1050         case CEE_CONV_OVF_I1:
1051         case CEE_CONV_OVF_U1:
1052         case CEE_CONV_OVF_I2:
1053         case CEE_CONV_OVF_U2:
1054         case CEE_CONV_OVF_I4:
1055         case CEE_CONV_OVF_U4:
1056                 ins->type = STACK_I4;
1057                 ins->opcode += ovf3ops_op_map [src1->type];
1058                 break;
1059         case CEE_CONV_OVF_I_UN:
1060         case CEE_CONV_OVF_U_UN:
1061                 ins->type = STACK_PTR;
1062                 ins->opcode += ovf2ops_op_map [src1->type];
1063                 break;
1064         case CEE_CONV_OVF_I1_UN:
1065         case CEE_CONV_OVF_I2_UN:
1066         case CEE_CONV_OVF_I4_UN:
1067         case CEE_CONV_OVF_U1_UN:
1068         case CEE_CONV_OVF_U2_UN:
1069         case CEE_CONV_OVF_U4_UN:
1070                 ins->type = STACK_I4;
1071                 ins->opcode += ovf2ops_op_map [src1->type];
1072                 break;
1073         case CEE_CONV_U:
1074                 ins->type = STACK_PTR;
1075                 switch (src1->type) {
1076                 case STACK_I4:
1077                         ins->opcode = OP_ICONV_TO_U;
1078                         break;
1079                 case STACK_PTR:
1080                 case STACK_MP:
1081 #if SIZEOF_VOID_P == 8
1082                         ins->opcode = OP_LCONV_TO_U;
1083 #else
1084                         ins->opcode = OP_MOVE;
1085 #endif
1086                         break;
1087                 case STACK_I8:
1088                         ins->opcode = OP_LCONV_TO_U;
1089                         break;
1090                 case STACK_R8:
1091                         ins->opcode = OP_FCONV_TO_U;
1092                         break;
1093                 }
1094                 break;
1095         case CEE_CONV_I8:
1096         case CEE_CONV_U8:
1097                 ins->type = STACK_I8;
1098                 ins->opcode += unops_op_map [src1->type];
1099                 break;
1100         case CEE_CONV_OVF_I8:
1101         case CEE_CONV_OVF_U8:
1102                 ins->type = STACK_I8;
1103                 ins->opcode += ovf3ops_op_map [src1->type];
1104                 break;
1105         case CEE_CONV_OVF_U8_UN:
1106         case CEE_CONV_OVF_I8_UN:
1107                 ins->type = STACK_I8;
1108                 ins->opcode += ovf2ops_op_map [src1->type];
1109                 break;
1110         case CEE_CONV_R4:
1111                 ins->type = cfg->r4_stack_type;
1112                 ins->opcode += unops_op_map [src1->type];
1113                 break;
1114         case CEE_CONV_R8:
1115                 ins->type = STACK_R8;
1116                 ins->opcode += unops_op_map [src1->type];
1117                 break;
1118         case OP_CKFINITE:
1119                 ins->type = STACK_R8;           
1120                 break;
1121         case CEE_CONV_U2:
1122         case CEE_CONV_U1:
1123                 ins->type = STACK_I4;
1124                 ins->opcode += ovfops_op_map [src1->type];
1125                 break;
1126         case CEE_CONV_I:
1127         case CEE_CONV_OVF_I:
1128         case CEE_CONV_OVF_U:
1129                 ins->type = STACK_PTR;
1130                 ins->opcode += ovfops_op_map [src1->type];
1131                 break;
1132         case CEE_ADD_OVF:
1133         case CEE_ADD_OVF_UN:
1134         case CEE_MUL_OVF:
1135         case CEE_MUL_OVF_UN:
1136         case CEE_SUB_OVF:
1137         case CEE_SUB_OVF_UN:
1138                 ins->type = bin_num_table [src1->type] [src2->type];
1139                 ins->opcode += ovfops_op_map [src1->type];
1140                 if (ins->type == STACK_R8)
1141                         ins->type = STACK_INV;
1142                 break;
1143         case OP_LOAD_MEMBASE:
1144                 ins->type = STACK_PTR;
1145                 break;
1146         case OP_LOADI1_MEMBASE:
1147         case OP_LOADU1_MEMBASE:
1148         case OP_LOADI2_MEMBASE:
1149         case OP_LOADU2_MEMBASE:
1150         case OP_LOADI4_MEMBASE:
1151         case OP_LOADU4_MEMBASE:
1152                 ins->type = STACK_PTR;
1153                 break;
1154         case OP_LOADI8_MEMBASE:
1155                 ins->type = STACK_I8;
1156                 break;
1157         case OP_LOADR4_MEMBASE:
1158                 ins->type = cfg->r4_stack_type;
1159                 break;
1160         case OP_LOADR8_MEMBASE:
1161                 ins->type = STACK_R8;
1162                 break;
1163         default:
1164                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1165                 break;
1166         }
1167
1168         if (ins->type == STACK_MP)
1169                 ins->klass = mono_defaults.object_class;
1170 }
1171
1172 static const char 
1173 ldind_type [] = {
1174         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1175 };
1176
1177 #if 0
1178
1179 static const char
1180 param_table [STACK_MAX] [STACK_MAX] = {
1181         {0},
1182 };
1183
1184 static int
1185 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1186 {
1187         int i;
1188
1189         if (sig->hasthis) {
1190                 switch (args->type) {
1191                 case STACK_I4:
1192                 case STACK_I8:
1193                 case STACK_R8:
1194                 case STACK_VTYPE:
1195                 case STACK_INV:
1196                         return 0;
1197                 }
1198                 args++;
1199         }
1200         for (i = 0; i < sig->param_count; ++i) {
1201                 switch (args [i].type) {
1202                 case STACK_INV:
1203                         return 0;
1204                 case STACK_MP:
1205                         if (!sig->params [i]->byref)
1206                                 return 0;
1207                         continue;
1208                 case STACK_OBJ:
1209                         if (sig->params [i]->byref)
1210                                 return 0;
1211                         switch (sig->params [i]->type) {
1212                         case MONO_TYPE_CLASS:
1213                         case MONO_TYPE_STRING:
1214                         case MONO_TYPE_OBJECT:
1215                         case MONO_TYPE_SZARRAY:
1216                         case MONO_TYPE_ARRAY:
1217                                 break;
1218                         default:
1219                                 return 0;
1220                         }
1221                         continue;
1222                 case STACK_R8:
1223                         if (sig->params [i]->byref)
1224                                 return 0;
1225                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1226                                 return 0;
1227                         continue;
1228                 case STACK_PTR:
1229                 case STACK_I4:
1230                 case STACK_I8:
1231                 case STACK_VTYPE:
1232                         break;
1233                 }
1234                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1235                         return 0;*/
1236         }
1237         return 1;
1238 }
1239 #endif
1240
1241 /*
1242  * When we need a pointer to the current domain many times in a method, we
1243  * call mono_domain_get() once and we store the result in a local variable.
1244  * This function returns the variable that represents the MonoDomain*.
1245  */
1246 inline static MonoInst *
1247 mono_get_domainvar (MonoCompile *cfg)
1248 {
1249         if (!cfg->domainvar)
1250                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1251         return cfg->domainvar;
1252 }
1253
1254 /*
1255  * The got_var contains the address of the Global Offset Table when AOT 
1256  * compiling.
1257  */
1258 MonoInst *
1259 mono_get_got_var (MonoCompile *cfg)
1260 {
1261         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1262                 return NULL;
1263         if (!cfg->got_var) {
1264                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1265         }
1266         return cfg->got_var;
1267 }
1268
1269 static MonoInst *
1270 mono_get_vtable_var (MonoCompile *cfg)
1271 {
1272         g_assert (cfg->gshared);
1273
1274         if (!cfg->rgctx_var) {
1275                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1276                 /* force the var to be stack allocated */
1277                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1278         }
1279
1280         return cfg->rgctx_var;
1281 }
1282
1283 static MonoType*
1284 type_from_stack_type (MonoInst *ins) {
1285         switch (ins->type) {
1286         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1287         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1288         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1289         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1290         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1291         case STACK_MP:
1292                 return &ins->klass->this_arg;
1293         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1294         case STACK_VTYPE: return &ins->klass->byval_arg;
1295         default:
1296                 g_error ("stack type %d to monotype not handled\n", ins->type);
1297         }
1298         return NULL;
1299 }
1300
1301 static G_GNUC_UNUSED int
1302 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1303 {
1304         t = mono_type_get_underlying_type (t);
1305         switch (t->type) {
1306         case MONO_TYPE_I1:
1307         case MONO_TYPE_U1:
1308         case MONO_TYPE_I2:
1309         case MONO_TYPE_U2:
1310         case MONO_TYPE_I4:
1311         case MONO_TYPE_U4:
1312                 return STACK_I4;
1313         case MONO_TYPE_I:
1314         case MONO_TYPE_U:
1315         case MONO_TYPE_PTR:
1316         case MONO_TYPE_FNPTR:
1317                 return STACK_PTR;
1318         case MONO_TYPE_CLASS:
1319         case MONO_TYPE_STRING:
1320         case MONO_TYPE_OBJECT:
1321         case MONO_TYPE_SZARRAY:
1322         case MONO_TYPE_ARRAY:    
1323                 return STACK_OBJ;
1324         case MONO_TYPE_I8:
1325         case MONO_TYPE_U8:
1326                 return STACK_I8;
1327         case MONO_TYPE_R4:
1328                 return cfg->r4_stack_type;
1329         case MONO_TYPE_R8:
1330                 return STACK_R8;
1331         case MONO_TYPE_VALUETYPE:
1332         case MONO_TYPE_TYPEDBYREF:
1333                 return STACK_VTYPE;
1334         case MONO_TYPE_GENERICINST:
1335                 if (mono_type_generic_inst_is_valuetype (t))
1336                         return STACK_VTYPE;
1337                 else
1338                         return STACK_OBJ;
1339                 break;
1340         default:
1341                 g_assert_not_reached ();
1342         }
1343
1344         return -1;
1345 }
1346
1347 static MonoClass*
1348 array_access_to_klass (int opcode)
1349 {
1350         switch (opcode) {
1351         case CEE_LDELEM_U1:
1352                 return mono_defaults.byte_class;
1353         case CEE_LDELEM_U2:
1354                 return mono_defaults.uint16_class;
1355         case CEE_LDELEM_I:
1356         case CEE_STELEM_I:
1357                 return mono_defaults.int_class;
1358         case CEE_LDELEM_I1:
1359         case CEE_STELEM_I1:
1360                 return mono_defaults.sbyte_class;
1361         case CEE_LDELEM_I2:
1362         case CEE_STELEM_I2:
1363                 return mono_defaults.int16_class;
1364         case CEE_LDELEM_I4:
1365         case CEE_STELEM_I4:
1366                 return mono_defaults.int32_class;
1367         case CEE_LDELEM_U4:
1368                 return mono_defaults.uint32_class;
1369         case CEE_LDELEM_I8:
1370         case CEE_STELEM_I8:
1371                 return mono_defaults.int64_class;
1372         case CEE_LDELEM_R4:
1373         case CEE_STELEM_R4:
1374                 return mono_defaults.single_class;
1375         case CEE_LDELEM_R8:
1376         case CEE_STELEM_R8:
1377                 return mono_defaults.double_class;
1378         case CEE_LDELEM_REF:
1379         case CEE_STELEM_REF:
1380                 return mono_defaults.object_class;
1381         default:
1382                 g_assert_not_reached ();
1383         }
1384         return NULL;
1385 }
1386
1387 /*
1388  * We try to share variables when possible
1389  */
1390 static MonoInst *
1391 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1392 {
1393         MonoInst *res;
1394         int pos, vnum;
1395
1396         /* inlining can result in deeper stacks */ 
1397         if (slot >= cfg->header->max_stack)
1398                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1399
1400         pos = ins->type - 1 + slot * STACK_MAX;
1401
1402         switch (ins->type) {
1403         case STACK_I4:
1404         case STACK_I8:
1405         case STACK_R8:
1406         case STACK_PTR:
1407         case STACK_MP:
1408         case STACK_OBJ:
1409                 if ((vnum = cfg->intvars [pos]))
1410                         return cfg->varinfo [vnum];
1411                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1412                 cfg->intvars [pos] = res->inst_c0;
1413                 break;
1414         default:
1415                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1416         }
1417         return res;
1418 }
1419
1420 static void
1421 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1422 {
1423         /* 
1424          * Don't use this if a generic_context is set, since that means AOT can't
1425          * look up the method using just the image+token.
1426          * table == 0 means this is a reference made from a wrapper.
1427          */
1428         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1429                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1430                 jump_info_token->image = image;
1431                 jump_info_token->token = token;
1432                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1433         }
1434 }
1435
1436 /*
1437  * This function is called to handle items that are left on the evaluation stack
1438  * at basic block boundaries. What happens is that we save the values to local variables
1439  * and we reload them later when first entering the target basic block (with the
1440  * handle_loaded_temps () function).
1441  * A single joint point will use the same variables (stored in the array bb->out_stack or
1442  * bb->in_stack, if the basic block is before or after the joint point).
1443  *
1444  * This function needs to be called _before_ emitting the last instruction of
1445  * the bb (i.e. before emitting a branch).
1446  * If the stack merge fails at a join point, cfg->unverifiable is set.
1447  */
1448 static void
1449 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1450 {
1451         int i, bindex;
1452         MonoBasicBlock *bb = cfg->cbb;
1453         MonoBasicBlock *outb;
1454         MonoInst *inst, **locals;
1455         gboolean found;
1456
1457         if (!count)
1458                 return;
1459         if (cfg->verbose_level > 3)
1460                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1461         if (!bb->out_scount) {
1462                 bb->out_scount = count;
1463                 //printf ("bblock %d has out:", bb->block_num);
1464                 found = FALSE;
1465                 for (i = 0; i < bb->out_count; ++i) {
1466                         outb = bb->out_bb [i];
1467                         /* exception handlers are linked, but they should not be considered for stack args */
1468                         if (outb->flags & BB_EXCEPTION_HANDLER)
1469                                 continue;
1470                         //printf (" %d", outb->block_num);
1471                         if (outb->in_stack) {
1472                                 found = TRUE;
1473                                 bb->out_stack = outb->in_stack;
1474                                 break;
1475                         }
1476                 }
1477                 //printf ("\n");
1478                 if (!found) {
1479                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1480                         for (i = 0; i < count; ++i) {
1481                                 /* 
1482                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1483                                  * stack slot and if they are of the same type.
1484                                  * This won't cause conflicts since if 'local' is used to 
1485                                  * store one of the values in the in_stack of a bblock, then
1486                                  * the same variable will be used for the same outgoing stack 
1487                                  * slot as well. 
1488                                  * This doesn't work when inlining methods, since the bblocks
1489                                  * in the inlined methods do not inherit their in_stack from
1490                                  * the bblock they are inlined to. See bug #58863 for an
1491                                  * example.
1492                                  */
1493                                 if (cfg->inlined_method)
1494                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1495                                 else
1496                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1497                         }
1498                 }
1499         }
1500
1501         for (i = 0; i < bb->out_count; ++i) {
1502                 outb = bb->out_bb [i];
1503                 /* exception handlers are linked, but they should not be considered for stack args */
1504                 if (outb->flags & BB_EXCEPTION_HANDLER)
1505                         continue;
1506                 if (outb->in_scount) {
1507                         if (outb->in_scount != bb->out_scount) {
1508                                 cfg->unverifiable = TRUE;
1509                                 return;
1510                         }
1511                         continue; /* check they are the same locals */
1512                 }
1513                 outb->in_scount = count;
1514                 outb->in_stack = bb->out_stack;
1515         }
1516
1517         locals = bb->out_stack;
1518         cfg->cbb = bb;
1519         for (i = 0; i < count; ++i) {
1520                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1521                 inst->cil_code = sp [i]->cil_code;
1522                 sp [i] = locals [i];
1523                 if (cfg->verbose_level > 3)
1524                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1525         }
1526
1527         /*
1528          * It is possible that the out bblocks already have in_stack assigned, and
1529          * the in_stacks differ. In this case, we will store to all the different 
1530          * in_stacks.
1531          */
1532
1533         found = TRUE;
1534         bindex = 0;
1535         while (found) {
1536                 /* Find a bblock which has a different in_stack */
1537                 found = FALSE;
1538                 while (bindex < bb->out_count) {
1539                         outb = bb->out_bb [bindex];
1540                         /* exception handlers are linked, but they should not be considered for stack args */
1541                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1542                                 bindex++;
1543                                 continue;
1544                         }
1545                         if (outb->in_stack != locals) {
1546                                 for (i = 0; i < count; ++i) {
1547                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1548                                         inst->cil_code = sp [i]->cil_code;
1549                                         sp [i] = locals [i];
1550                                         if (cfg->verbose_level > 3)
1551                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1552                                 }
1553                                 locals = outb->in_stack;
1554                                 found = TRUE;
1555                                 break;
1556                         }
1557                         bindex ++;
1558                 }
1559         }
1560 }
1561
1562 static MonoInst*
1563 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1564 {
1565         MonoInst *ins;
1566
1567         if (cfg->compile_aot) {
1568                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1569         } else {
1570                 MonoJumpInfo ji;
1571                 gpointer target;
1572                 MonoError error;
1573
1574                 ji.type = patch_type;
1575                 ji.data.target = data;
1576                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1577                 mono_error_assert_ok (&error);
1578
1579                 EMIT_NEW_PCONST (cfg, ins, target);
1580         }
1581         return ins;
1582 }
1583
1584 MonoInst*
1585 mini_emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1586 {
1587         return emit_runtime_constant (cfg, patch_type, data);
1588 }
1589
1590 static void 
1591 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1592 {
1593         int val_reg;
1594
1595         g_assert (val == 0);
1596
1597         if (align == 0)
1598                 align = 4;
1599
1600         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1601                 switch (size) {
1602                 case 1:
1603                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1604                         return;
1605                 case 2:
1606                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1607                         return;
1608                 case 4:
1609                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1610                         return;
1611 #if SIZEOF_REGISTER == 8
1612                 case 8:
1613                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1614                         return;
1615 #endif
1616                 }
1617         }
1618
1619         val_reg = alloc_preg (cfg);
1620
1621         if (SIZEOF_REGISTER == 8)
1622                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1623         else
1624                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1625
1626         if (align < 4) {
1627                 /* This could be optimized further if neccesary */
1628                 while (size >= 1) {
1629                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1630                         offset += 1;
1631                         size -= 1;
1632                 }
1633                 return;
1634         }       
1635
1636         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1637                 if (offset % 8) {
1638                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1639                         offset += 4;
1640                         size -= 4;
1641                 }
1642                 while (size >= 8) {
1643                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1644                         offset += 8;
1645                         size -= 8;
1646                 }
1647         }       
1648
1649         while (size >= 4) {
1650                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1651                 offset += 4;
1652                 size -= 4;
1653         }
1654         while (size >= 2) {
1655                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1656                 offset += 2;
1657                 size -= 2;
1658         }
1659         while (size >= 1) {
1660                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1661                 offset += 1;
1662                 size -= 1;
1663         }
1664 }
1665
1666 void 
1667 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1668 {
1669         int cur_reg;
1670
1671         if (align == 0)
1672                 align = 4;
1673
1674         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1675         g_assert (size < 10000);
1676
1677         if (align < 4) {
1678                 /* This could be optimized further if neccesary */
1679                 while (size >= 1) {
1680                         cur_reg = alloc_preg (cfg);
1681                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1682                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1683                         doffset += 1;
1684                         soffset += 1;
1685                         size -= 1;
1686                 }
1687         }
1688
1689         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1690                 while (size >= 8) {
1691                         cur_reg = alloc_preg (cfg);
1692                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1693                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1694                         doffset += 8;
1695                         soffset += 8;
1696                         size -= 8;
1697                 }
1698         }       
1699
1700         while (size >= 4) {
1701                 cur_reg = alloc_preg (cfg);
1702                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1703                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1704                 doffset += 4;
1705                 soffset += 4;
1706                 size -= 4;
1707         }
1708         while (size >= 2) {
1709                 cur_reg = alloc_preg (cfg);
1710                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1711                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1712                 doffset += 2;
1713                 soffset += 2;
1714                 size -= 2;
1715         }
1716         while (size >= 1) {
1717                 cur_reg = alloc_preg (cfg);
1718                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1719                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1720                 doffset += 1;
1721                 soffset += 1;
1722                 size -= 1;
1723         }
1724 }
1725
1726 static MonoInst*
1727 mono_create_fast_tls_getter (MonoCompile *cfg, MonoTlsKey key)
1728 {
1729         int tls_offset = mono_tls_get_tls_offset (key);
1730
1731         if (cfg->compile_aot)
1732                 return NULL;
1733
1734         if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
1735                 MonoInst *ins;
1736                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
1737                 ins->dreg = mono_alloc_preg (cfg);
1738                 ins->inst_offset = tls_offset;
1739                 return ins;
1740         }
1741         return NULL;
1742 }
1743
1744 static MonoInst*
1745 mono_create_fast_tls_setter (MonoCompile *cfg, MonoInst* value, MonoTlsKey key)
1746 {
1747         int tls_offset = mono_tls_get_tls_offset (key);
1748
1749         if (cfg->compile_aot)
1750                 return NULL;
1751
1752         if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
1753                 MonoInst *ins;
1754                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1755                 ins->sreg1 = value->dreg;
1756                 ins->inst_offset = tls_offset;
1757                 return ins;
1758         }
1759         return NULL;
1760 }
1761
1762
1763 MonoInst*
1764 mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key)
1765 {
1766         MonoInst *fast_tls = NULL;
1767
1768         if (!mini_get_debug_options ()->use_fallback_tls)
1769                 fast_tls = mono_create_fast_tls_getter (cfg, key);
1770
1771         if (fast_tls) {
1772                 MONO_ADD_INS (cfg->cbb, fast_tls);
1773                 return fast_tls;
1774         }
1775
1776         if (cfg->compile_aot) {
1777                 MonoInst *addr;
1778                 /*
1779                  * tls getters are critical pieces of code and we don't want to resolve them
1780                  * through the standard plt/tramp mechanism since we might expose ourselves
1781                  * to crashes and infinite recursions.
1782                  */
1783                 EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GET_TLS_TRAMP, (void*)key);
1784                 return mono_emit_calli (cfg, helper_sig_get_tls_tramp, NULL, addr, NULL, NULL);
1785         } else {
1786                 gpointer getter = mono_tls_get_tls_getter (key, FALSE);
1787                 return mono_emit_jit_icall (cfg, getter, NULL);
1788         }
1789 }
1790
1791 static MonoInst*
1792 mono_create_tls_set (MonoCompile *cfg, MonoInst *value, MonoTlsKey key)
1793 {
1794         MonoInst *fast_tls = NULL;
1795
1796         if (!mini_get_debug_options ()->use_fallback_tls)
1797                 fast_tls = mono_create_fast_tls_setter (cfg, value, key);
1798
1799         if (fast_tls) {
1800                 MONO_ADD_INS (cfg->cbb, fast_tls);
1801                 return fast_tls;
1802         }
1803
1804         if (cfg->compile_aot) {
1805                 MonoInst *addr;
1806                 EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_SET_TLS_TRAMP, (void*)key);
1807                 return mono_emit_calli (cfg, helper_sig_set_tls_tramp, &value, addr, NULL, NULL);
1808         } else {
1809                 gpointer setter = mono_tls_get_tls_setter (key, FALSE);
1810                 return mono_emit_jit_icall (cfg, setter, &value);
1811         }
1812 }
1813
1814 /*
1815  * emit_push_lmf:
1816  *
1817  *   Emit IR to push the current LMF onto the LMF stack.
1818  */
1819 static void
1820 emit_push_lmf (MonoCompile *cfg)
1821 {
1822         /*
1823          * Emit IR to push the LMF:
1824          * lmf_addr = <lmf_addr from tls>
1825          * lmf->lmf_addr = lmf_addr
1826          * lmf->prev_lmf = *lmf_addr
1827          * *lmf_addr = lmf
1828          */
1829         MonoInst *ins, *lmf_ins;
1830
1831         if (!cfg->lmf_ir)
1832                 return;
1833
1834         if (cfg->lmf_ir_mono_lmf) {
1835                 MonoInst *lmf_vara_ins, *lmf_ins;
1836                 /* Load current lmf */
1837                 lmf_ins = mono_create_tls_get (cfg, TLS_KEY_LMF);
1838                 g_assert (lmf_ins);
1839                 EMIT_NEW_VARLOADA (cfg, lmf_vara_ins, cfg->lmf_var, NULL);
1840                 /* Save previous_lmf */
1841                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_vara_ins->dreg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1842                 /* Set new LMF */
1843                 mono_create_tls_set (cfg, lmf_vara_ins, TLS_KEY_LMF);
1844         } else {
1845                 int lmf_reg, prev_lmf_reg;
1846                 /*
1847                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1848                  */
1849                 if (!cfg->lmf_addr_var)
1850                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1851
1852 #ifdef HOST_WIN32
1853                 ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
1854                 g_assert (ins);
1855                 int jit_tls_dreg = ins->dreg;
1856
1857                 lmf_reg = alloc_preg (cfg);
1858                 EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
1859 #else
1860                 lmf_ins = mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR);
1861                 g_assert (lmf_ins);
1862 #endif
1863                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
1864
1865                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1866                 lmf_reg = ins->dreg;
1867
1868                 prev_lmf_reg = alloc_preg (cfg);
1869                 /* Save previous_lmf */
1870                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
1871                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
1872                 /* Set new lmf */
1873                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
1874         }
1875 }
1876
1877 /*
1878  * emit_pop_lmf:
1879  *
1880  *   Emit IR to pop the current LMF from the LMF stack.
1881  */
1882 static void
1883 emit_pop_lmf (MonoCompile *cfg)
1884 {
1885         int lmf_reg, lmf_addr_reg;
1886         MonoInst *ins;
1887
1888         if (!cfg->lmf_ir)
1889                 return;
1890
1891         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1892         lmf_reg = ins->dreg;
1893
1894         if (cfg->lmf_ir_mono_lmf) {
1895                 /* Load previous_lmf */
1896                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, alloc_preg (cfg), lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1897                 /* Set new LMF */
1898                 mono_create_tls_set (cfg, ins, TLS_KEY_LMF);
1899         } else {
1900                 int prev_lmf_reg;
1901                 /*
1902                  * Emit IR to pop the LMF:
1903                  * *(lmf->lmf_addr) = lmf->prev_lmf
1904                  */
1905                 /* This could be called before emit_push_lmf () */
1906                 if (!cfg->lmf_addr_var)
1907                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1908                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
1909
1910                 prev_lmf_reg = alloc_preg (cfg);
1911                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1912                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
1913         }
1914 }
1915
1916 static void
1917 emit_instrumentation_call (MonoCompile *cfg, void *func)
1918 {
1919         MonoInst *iargs [1];
1920
1921         /*
1922          * Avoid instrumenting inlined methods since it can
1923          * distort profiling results.
1924          */
1925         if (cfg->method != cfg->current_method)
1926                 return;
1927
1928         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
1929                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
1930                 mono_emit_jit_icall (cfg, func, iargs);
1931         }
1932 }
1933
1934 static int
1935 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
1936 {
1937 handle_enum:
1938         type = mini_get_underlying_type (type);
1939         switch (type->type) {
1940         case MONO_TYPE_VOID:
1941                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
1942         case MONO_TYPE_I1:
1943         case MONO_TYPE_U1:
1944         case MONO_TYPE_I2:
1945         case MONO_TYPE_U2:
1946         case MONO_TYPE_I4:
1947         case MONO_TYPE_U4:
1948                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1949         case MONO_TYPE_I:
1950         case MONO_TYPE_U:
1951         case MONO_TYPE_PTR:
1952         case MONO_TYPE_FNPTR:
1953                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1954         case MONO_TYPE_CLASS:
1955         case MONO_TYPE_STRING:
1956         case MONO_TYPE_OBJECT:
1957         case MONO_TYPE_SZARRAY:
1958         case MONO_TYPE_ARRAY:    
1959                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1960         case MONO_TYPE_I8:
1961         case MONO_TYPE_U8:
1962                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
1963         case MONO_TYPE_R4:
1964                 if (cfg->r4fp)
1965                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
1966                 else
1967                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1968         case MONO_TYPE_R8:
1969                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1970         case MONO_TYPE_VALUETYPE:
1971                 if (type->data.klass->enumtype) {
1972                         type = mono_class_enum_basetype (type->data.klass);
1973                         goto handle_enum;
1974                 } else
1975                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1976         case MONO_TYPE_TYPEDBYREF:
1977                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1978         case MONO_TYPE_GENERICINST:
1979                 type = &type->data.generic_class->container_class->byval_arg;
1980                 goto handle_enum;
1981         case MONO_TYPE_VAR:
1982         case MONO_TYPE_MVAR:
1983                 /* gsharedvt */
1984                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1985         default:
1986                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1987         }
1988         return -1;
1989 }
1990
1991 //XXX this ignores if t is byref
1992 #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)))))
1993
1994 /*
1995  * target_type_is_incompatible:
1996  * @cfg: MonoCompile context
1997  *
1998  * Check that the item @arg on the evaluation stack can be stored
1999  * in the target type (can be a local, or field, etc).
2000  * The cfg arg can be used to check if we need verification or just
2001  * validity checks.
2002  *
2003  * Returns: non-0 value if arg can't be stored on a target.
2004  */
2005 static int
2006 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2007 {
2008         MonoType *simple_type;
2009         MonoClass *klass;
2010
2011         if (target->byref) {
2012                 /* FIXME: check that the pointed to types match */
2013                 if (arg->type == STACK_MP) {
2014                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
2015                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
2016                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
2017
2018                         /* if the target is native int& or same type */
2019                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
2020                                 return 0;
2021
2022                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
2023                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
2024                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
2025                                 return 0;
2026                         return 1;
2027                 }
2028                 if (arg->type == STACK_PTR)
2029                         return 0;
2030                 return 1;
2031         }
2032
2033         simple_type = mini_get_underlying_type (target);
2034         switch (simple_type->type) {
2035         case MONO_TYPE_VOID:
2036                 return 1;
2037         case MONO_TYPE_I1:
2038         case MONO_TYPE_U1:
2039         case MONO_TYPE_I2:
2040         case MONO_TYPE_U2:
2041         case MONO_TYPE_I4:
2042         case MONO_TYPE_U4:
2043                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2044                         return 1;
2045                 return 0;
2046         case MONO_TYPE_PTR:
2047                 /* STACK_MP is needed when setting pinned locals */
2048                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2049                         return 1;
2050                 return 0;
2051         case MONO_TYPE_I:
2052         case MONO_TYPE_U:
2053         case MONO_TYPE_FNPTR:
2054                 /* 
2055                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2056                  * in native int. (#688008).
2057                  */
2058                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2059                         return 1;
2060                 return 0;
2061         case MONO_TYPE_CLASS:
2062         case MONO_TYPE_STRING:
2063         case MONO_TYPE_OBJECT:
2064         case MONO_TYPE_SZARRAY:
2065         case MONO_TYPE_ARRAY:    
2066                 if (arg->type != STACK_OBJ)
2067                         return 1;
2068                 /* FIXME: check type compatibility */
2069                 return 0;
2070         case MONO_TYPE_I8:
2071         case MONO_TYPE_U8:
2072                 if (arg->type != STACK_I8)
2073                         return 1;
2074                 return 0;
2075         case MONO_TYPE_R4:
2076                 if (arg->type != cfg->r4_stack_type)
2077                         return 1;
2078                 return 0;
2079         case MONO_TYPE_R8:
2080                 if (arg->type != STACK_R8)
2081                         return 1;
2082                 return 0;
2083         case MONO_TYPE_VALUETYPE:
2084                 if (arg->type != STACK_VTYPE)
2085                         return 1;
2086                 klass = mono_class_from_mono_type (simple_type);
2087                 if (klass != arg->klass)
2088                         return 1;
2089                 return 0;
2090         case MONO_TYPE_TYPEDBYREF:
2091                 if (arg->type != STACK_VTYPE)
2092                         return 1;
2093                 klass = mono_class_from_mono_type (simple_type);
2094                 if (klass != arg->klass)
2095                         return 1;
2096                 return 0;
2097         case MONO_TYPE_GENERICINST:
2098                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2099                         MonoClass *target_class;
2100                         if (arg->type != STACK_VTYPE)
2101                                 return 1;
2102                         klass = mono_class_from_mono_type (simple_type);
2103                         target_class = mono_class_from_mono_type (target);
2104                         /* The second cases is needed when doing partial sharing */
2105                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2106                                 return 1;
2107                         return 0;
2108                 } else {
2109                         if (arg->type != STACK_OBJ)
2110                                 return 1;
2111                         /* FIXME: check type compatibility */
2112                         return 0;
2113                 }
2114         case MONO_TYPE_VAR:
2115         case MONO_TYPE_MVAR:
2116                 g_assert (cfg->gshared);
2117                 if (mini_type_var_is_vt (simple_type)) {
2118                         if (arg->type != STACK_VTYPE)
2119                                 return 1;
2120                 } else {
2121                         if (arg->type != STACK_OBJ)
2122                                 return 1;
2123                 }
2124                 return 0;
2125         default:
2126                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2127         }
2128         return 1;
2129 }
2130
2131 /*
2132  * Prepare arguments for passing to a function call.
2133  * Return a non-zero value if the arguments can't be passed to the given
2134  * signature.
2135  * The type checks are not yet complete and some conversions may need
2136  * casts on 32 or 64 bit architectures.
2137  *
2138  * FIXME: implement this using target_type_is_incompatible ()
2139  */
2140 static int
2141 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2142 {
2143         MonoType *simple_type;
2144         int i;
2145
2146         if (sig->hasthis) {
2147                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2148                         return 1;
2149                 args++;
2150         }
2151         for (i = 0; i < sig->param_count; ++i) {
2152                 if (sig->params [i]->byref) {
2153                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2154                                 return 1;
2155                         continue;
2156                 }
2157                 simple_type = mini_get_underlying_type (sig->params [i]);
2158 handle_enum:
2159                 switch (simple_type->type) {
2160                 case MONO_TYPE_VOID:
2161                         return 1;
2162                         continue;
2163                 case MONO_TYPE_I1:
2164                 case MONO_TYPE_U1:
2165                 case MONO_TYPE_I2:
2166                 case MONO_TYPE_U2:
2167                 case MONO_TYPE_I4:
2168                 case MONO_TYPE_U4:
2169                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2170                                 return 1;
2171                         continue;
2172                 case MONO_TYPE_I:
2173                 case MONO_TYPE_U:
2174                 case MONO_TYPE_PTR:
2175                 case MONO_TYPE_FNPTR:
2176                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2177                                 return 1;
2178                         continue;
2179                 case MONO_TYPE_CLASS:
2180                 case MONO_TYPE_STRING:
2181                 case MONO_TYPE_OBJECT:
2182                 case MONO_TYPE_SZARRAY:
2183                 case MONO_TYPE_ARRAY:    
2184                         if (args [i]->type != STACK_OBJ)
2185                                 return 1;
2186                         continue;
2187                 case MONO_TYPE_I8:
2188                 case MONO_TYPE_U8:
2189                         if (args [i]->type != STACK_I8)
2190                                 return 1;
2191                         continue;
2192                 case MONO_TYPE_R4:
2193                         if (args [i]->type != cfg->r4_stack_type)
2194                                 return 1;
2195                         continue;
2196                 case MONO_TYPE_R8:
2197                         if (args [i]->type != STACK_R8)
2198                                 return 1;
2199                         continue;
2200                 case MONO_TYPE_VALUETYPE:
2201                         if (simple_type->data.klass->enumtype) {
2202                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2203                                 goto handle_enum;
2204                         }
2205                         if (args [i]->type != STACK_VTYPE)
2206                                 return 1;
2207                         continue;
2208                 case MONO_TYPE_TYPEDBYREF:
2209                         if (args [i]->type != STACK_VTYPE)
2210                                 return 1;
2211                         continue;
2212                 case MONO_TYPE_GENERICINST:
2213                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2214                         goto handle_enum;
2215                 case MONO_TYPE_VAR:
2216                 case MONO_TYPE_MVAR:
2217                         /* gsharedvt */
2218                         if (args [i]->type != STACK_VTYPE)
2219                                 return 1;
2220                         continue;
2221                 default:
2222                         g_error ("unknown type 0x%02x in check_call_signature",
2223                                  simple_type->type);
2224                 }
2225         }
2226         return 0;
2227 }
2228
2229 static int
2230 callvirt_to_call (int opcode)
2231 {
2232         switch (opcode) {
2233         case OP_CALL_MEMBASE:
2234                 return OP_CALL;
2235         case OP_VOIDCALL_MEMBASE:
2236                 return OP_VOIDCALL;
2237         case OP_FCALL_MEMBASE:
2238                 return OP_FCALL;
2239         case OP_RCALL_MEMBASE:
2240                 return OP_RCALL;
2241         case OP_VCALL_MEMBASE:
2242                 return OP_VCALL;
2243         case OP_LCALL_MEMBASE:
2244                 return OP_LCALL;
2245         default:
2246                 g_assert_not_reached ();
2247         }
2248
2249         return -1;
2250 }
2251
2252 static int
2253 callvirt_to_call_reg (int opcode)
2254 {
2255         switch (opcode) {
2256         case OP_CALL_MEMBASE:
2257                 return OP_CALL_REG;
2258         case OP_VOIDCALL_MEMBASE:
2259                 return OP_VOIDCALL_REG;
2260         case OP_FCALL_MEMBASE:
2261                 return OP_FCALL_REG;
2262         case OP_RCALL_MEMBASE:
2263                 return OP_RCALL_REG;
2264         case OP_VCALL_MEMBASE:
2265                 return OP_VCALL_REG;
2266         case OP_LCALL_MEMBASE:
2267                 return OP_LCALL_REG;
2268         default:
2269                 g_assert_not_reached ();
2270         }
2271
2272         return -1;
2273 }
2274
2275 /* Either METHOD or IMT_ARG needs to be set */
2276 static void
2277 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2278 {
2279         int method_reg;
2280
2281         if (COMPILE_LLVM (cfg)) {
2282                 if (imt_arg) {
2283                         method_reg = alloc_preg (cfg);
2284                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2285                 } else {
2286                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2287                         method_reg = ins->dreg;
2288                 }
2289
2290 #ifdef ENABLE_LLVM
2291                 call->imt_arg_reg = method_reg;
2292 #endif
2293                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2294                 return;
2295         }
2296
2297         if (imt_arg) {
2298                 method_reg = alloc_preg (cfg);
2299                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2300         } else {
2301                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2302                 method_reg = ins->dreg;
2303         }
2304
2305         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2306 }
2307
2308 static MonoJumpInfo *
2309 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2310 {
2311         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2312
2313         ji->ip.i = ip;
2314         ji->type = type;
2315         ji->data.target = target;
2316
2317         return ji;
2318 }
2319
2320 static int
2321 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2322 {
2323         if (cfg->gshared)
2324                 return mono_class_check_context_used (klass);
2325         else
2326                 return 0;
2327 }
2328
2329 static int
2330 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2331 {
2332         if (cfg->gshared)
2333                 return mono_method_check_context_used (method);
2334         else
2335                 return 0;
2336 }
2337
2338 /*
2339  * check_method_sharing:
2340  *
2341  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2342  */
2343 static void
2344 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2345 {
2346         gboolean pass_vtable = FALSE;
2347         gboolean pass_mrgctx = FALSE;
2348
2349         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2350                 (mono_class_is_ginst (cmethod->klass) || mono_class_is_gtd (cmethod->klass))) {
2351                 gboolean sharable = FALSE;
2352
2353                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2354                         sharable = TRUE;
2355
2356                 /*
2357                  * Pass vtable iff target method might
2358                  * be shared, which means that sharing
2359                  * is enabled for its class and its
2360                  * context is sharable (and it's not a
2361                  * generic method).
2362                  */
2363                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2364                         pass_vtable = TRUE;
2365         }
2366
2367         if (mini_method_get_context (cmethod) &&
2368                 mini_method_get_context (cmethod)->method_inst) {
2369                 g_assert (!pass_vtable);
2370
2371                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2372                         pass_mrgctx = TRUE;
2373                 } else {
2374                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2375                                 pass_mrgctx = TRUE;
2376                 }
2377         }
2378
2379         if (out_pass_vtable)
2380                 *out_pass_vtable = pass_vtable;
2381         if (out_pass_mrgctx)
2382                 *out_pass_mrgctx = pass_mrgctx;
2383 }
2384
2385 inline static MonoCallInst *
2386 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2387                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2388 {
2389         MonoType *sig_ret;
2390         MonoCallInst *call;
2391 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2392         int i;
2393 #endif
2394
2395         if (cfg->llvm_only)
2396                 tail = FALSE;
2397
2398         if (tail) {
2399                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2400
2401                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2402         } else
2403                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2404
2405         call->args = args;
2406         call->signature = sig;
2407         call->rgctx_reg = rgctx;
2408         sig_ret = mini_get_underlying_type (sig->ret);
2409
2410         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2411
2412         if (tail) {
2413                 if (mini_type_is_vtype (sig_ret)) {
2414                         call->vret_var = cfg->vret_addr;
2415                         //g_assert_not_reached ();
2416                 }
2417         } else if (mini_type_is_vtype (sig_ret)) {
2418                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2419                 MonoInst *loada;
2420
2421                 temp->backend.is_pinvoke = sig->pinvoke;
2422
2423                 /*
2424                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2425                  * address of return value to increase optimization opportunities.
2426                  * Before vtype decomposition, the dreg of the call ins itself represents the
2427                  * fact the call modifies the return value. After decomposition, the call will
2428                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2429                  * will be transformed into an LDADDR.
2430                  */
2431                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2432                 loada->dreg = alloc_preg (cfg);
2433                 loada->inst_p0 = temp;
2434                 /* We reference the call too since call->dreg could change during optimization */
2435                 loada->inst_p1 = call;
2436                 MONO_ADD_INS (cfg->cbb, loada);
2437
2438                 call->inst.dreg = temp->dreg;
2439
2440                 call->vret_var = loada;
2441         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2442                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2443
2444 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2445         if (COMPILE_SOFT_FLOAT (cfg)) {
2446                 /* 
2447                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2448                  * an icall, but that cannot be done during the call sequence since it would clobber
2449                  * the call registers + the stack. So we do it before emitting the call.
2450                  */
2451                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2452                         MonoType *t;
2453                         MonoInst *in = call->args [i];
2454
2455                         if (i >= sig->hasthis)
2456                                 t = sig->params [i - sig->hasthis];
2457                         else
2458                                 t = &mono_defaults.int_class->byval_arg;
2459                         t = mono_type_get_underlying_type (t);
2460
2461                         if (!t->byref && t->type == MONO_TYPE_R4) {
2462                                 MonoInst *iargs [1];
2463                                 MonoInst *conv;
2464
2465                                 iargs [0] = in;
2466                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2467
2468                                 /* The result will be in an int vreg */
2469                                 call->args [i] = conv;
2470                         }
2471                 }
2472         }
2473 #endif
2474
2475         call->need_unbox_trampoline = unbox_trampoline;
2476
2477 #ifdef ENABLE_LLVM
2478         if (COMPILE_LLVM (cfg))
2479                 mono_llvm_emit_call (cfg, call);
2480         else
2481                 mono_arch_emit_call (cfg, call);
2482 #else
2483         mono_arch_emit_call (cfg, call);
2484 #endif
2485
2486         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2487         cfg->flags |= MONO_CFG_HAS_CALLS;
2488         
2489         return call;
2490 }
2491
2492 static void
2493 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2494 {
2495         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2496         cfg->uses_rgctx_reg = TRUE;
2497         call->rgctx_reg = TRUE;
2498 #ifdef ENABLE_LLVM
2499         call->rgctx_arg_reg = rgctx_reg;
2500 #endif
2501 }       
2502
2503 inline static MonoInst*
2504 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2505 {
2506         MonoCallInst *call;
2507         MonoInst *ins;
2508         int rgctx_reg = -1;
2509         gboolean check_sp = FALSE;
2510
2511         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2512                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2513
2514                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2515                         check_sp = TRUE;
2516         }
2517
2518         if (rgctx_arg) {
2519                 rgctx_reg = mono_alloc_preg (cfg);
2520                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2521         }
2522
2523         if (check_sp) {
2524                 if (!cfg->stack_inbalance_var)
2525                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2526
2527                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2528                 ins->dreg = cfg->stack_inbalance_var->dreg;
2529                 MONO_ADD_INS (cfg->cbb, ins);
2530         }
2531
2532         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2533
2534         call->inst.sreg1 = addr->dreg;
2535
2536         if (imt_arg)
2537                 emit_imt_argument (cfg, call, NULL, imt_arg);
2538
2539         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2540
2541         if (check_sp) {
2542                 int sp_reg;
2543
2544                 sp_reg = mono_alloc_preg (cfg);
2545
2546                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2547                 ins->dreg = sp_reg;
2548                 MONO_ADD_INS (cfg->cbb, ins);
2549
2550                 /* Restore the stack so we don't crash when throwing the exception */
2551                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2552                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2553                 MONO_ADD_INS (cfg->cbb, ins);
2554
2555                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2556                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2557         }
2558
2559         if (rgctx_arg)
2560                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2561
2562         return (MonoInst*)call;
2563 }
2564
2565 static MonoInst*
2566 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2567
2568 static MonoInst*
2569 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2570
2571 static MonoInst*
2572 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2573                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2574 {
2575 #ifndef DISABLE_REMOTING
2576         gboolean might_be_remote = FALSE;
2577 #endif
2578         gboolean virtual_ = this_ins != NULL;
2579         gboolean enable_for_aot = TRUE;
2580         int context_used;
2581         MonoCallInst *call;
2582         MonoInst *call_target = NULL;
2583         int rgctx_reg = 0;
2584         gboolean need_unbox_trampoline;
2585
2586         if (!sig)
2587                 sig = mono_method_signature (method);
2588
2589         if (cfg->llvm_only && (mono_class_is_interface (method->klass)))
2590                 g_assert_not_reached ();
2591
2592         if (rgctx_arg) {
2593                 rgctx_reg = mono_alloc_preg (cfg);
2594                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2595         }
2596
2597         if (method->string_ctor) {
2598                 /* Create the real signature */
2599                 /* FIXME: Cache these */
2600                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2601                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2602
2603                 sig = ctor_sig;
2604         }
2605
2606         context_used = mini_method_check_context_used (cfg, method);
2607
2608 #ifndef DISABLE_REMOTING
2609         might_be_remote = this_ins && sig->hasthis &&
2610                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2611                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2612
2613         if (might_be_remote && context_used) {
2614                 MonoInst *addr;
2615
2616                 g_assert (cfg->gshared);
2617
2618                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2619
2620                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2621         }
2622 #endif
2623
2624         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2625                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2626
2627         need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass);
2628
2629         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2630
2631 #ifndef DISABLE_REMOTING
2632         if (might_be_remote)
2633                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2634         else
2635 #endif
2636                 call->method = method;
2637         call->inst.flags |= MONO_INST_HAS_METHOD;
2638         call->inst.inst_left = this_ins;
2639         call->tail_call = tail;
2640
2641         if (virtual_) {
2642                 int vtable_reg, slot_reg, this_reg;
2643                 int offset;
2644
2645                 this_reg = this_ins->dreg;
2646
2647                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2648                         MonoInst *dummy_use;
2649
2650                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2651
2652                         /* Make a call to delegate->invoke_impl */
2653                         call->inst.inst_basereg = this_reg;
2654                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2655                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2656
2657                         /* We must emit a dummy use here because the delegate trampoline will
2658                         replace the 'this' argument with the delegate target making this activation
2659                         no longer a root for the delegate.
2660                         This is an issue for delegates that target collectible code such as dynamic
2661                         methods of GC'able assemblies.
2662
2663                         For a test case look into #667921.
2664
2665                         FIXME: a dummy use is not the best way to do it as the local register allocator
2666                         will put it on a caller save register and spil it around the call. 
2667                         Ideally, we would either put it on a callee save register or only do the store part.  
2668                          */
2669                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2670
2671                         return (MonoInst*)call;
2672                 }
2673
2674                 if ((!cfg->compile_aot || enable_for_aot) && 
2675                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2676                          (MONO_METHOD_IS_FINAL (method) &&
2677                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2678                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2679                         /* 
2680                          * the method is not virtual, we just need to ensure this is not null
2681                          * and then we can call the method directly.
2682                          */
2683 #ifndef DISABLE_REMOTING
2684                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2685                                 /* 
2686                                  * The check above ensures method is not gshared, this is needed since
2687                                  * gshared methods can't have wrappers.
2688                                  */
2689                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2690                         }
2691 #endif
2692
2693                         if (!method->string_ctor)
2694                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2695
2696                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2697                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2698                         /*
2699                          * the method is virtual, but we can statically dispatch since either
2700                          * it's class or the method itself are sealed.
2701                          * But first we need to ensure it's not a null reference.
2702                          */
2703                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2704
2705                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2706                 } else if (call_target) {
2707                         vtable_reg = alloc_preg (cfg);
2708                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2709
2710                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2711                         call->inst.sreg1 = call_target->dreg;
2712                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2713                 } else {
2714                         vtable_reg = alloc_preg (cfg);
2715                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2716                         if (mono_class_is_interface (method->klass)) {
2717                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2718                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2719                                 slot_reg = vtable_reg;
2720                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2721                         } else {
2722                                 slot_reg = vtable_reg;
2723                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2724                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2725                                 if (imt_arg) {
2726                                         g_assert (mono_method_signature (method)->generic_param_count);
2727                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2728                                 }
2729                         }
2730
2731                         call->inst.sreg1 = slot_reg;
2732                         call->inst.inst_offset = offset;
2733                         call->is_virtual = TRUE;
2734                 }
2735         }
2736
2737         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2738
2739         if (rgctx_arg)
2740                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2741
2742         return (MonoInst*)call;
2743 }
2744
2745 MonoInst*
2746 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2747 {
2748         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2749 }
2750
2751 MonoInst*
2752 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2753                                            MonoInst **args)
2754 {
2755         MonoCallInst *call;
2756
2757         g_assert (sig);
2758
2759         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2760         call->fptr = func;
2761
2762         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2763
2764         return (MonoInst*)call;
2765 }
2766
2767 MonoInst*
2768 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2769 {
2770         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2771
2772         g_assert (info);
2773
2774         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2775 }
2776
2777 /*
2778  * mono_emit_abs_call:
2779  *
2780  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2781  */
2782 inline static MonoInst*
2783 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2784                                         MonoMethodSignature *sig, MonoInst **args)
2785 {
2786         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2787         MonoInst *ins;
2788
2789         /* 
2790          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2791          * handle it.
2792          */
2793         if (cfg->abs_patches == NULL)
2794                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2795         g_hash_table_insert (cfg->abs_patches, ji, ji);
2796         ins = mono_emit_native_call (cfg, ji, sig, args);
2797         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2798         return ins;
2799 }
2800
2801 static MonoMethodSignature*
2802 sig_to_rgctx_sig (MonoMethodSignature *sig)
2803 {
2804         // FIXME: memory allocation
2805         MonoMethodSignature *res;
2806         int i;
2807
2808         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2809         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2810         res->param_count = sig->param_count + 1;
2811         for (i = 0; i < sig->param_count; ++i)
2812                 res->params [i] = sig->params [i];
2813         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
2814         return res;
2815 }
2816
2817 /* Make an indirect call to FSIG passing an additional argument */
2818 static MonoInst*
2819 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
2820 {
2821         MonoMethodSignature *csig;
2822         MonoInst *args_buf [16];
2823         MonoInst **args;
2824         int i, pindex, tmp_reg;
2825
2826         /* Make a call with an rgctx/extra arg */
2827         if (fsig->param_count + 2 < 16)
2828                 args = args_buf;
2829         else
2830                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
2831         pindex = 0;
2832         if (fsig->hasthis)
2833                 args [pindex ++] = orig_args [0];
2834         for (i = 0; i < fsig->param_count; ++i)
2835                 args [pindex ++] = orig_args [fsig->hasthis + i];
2836         tmp_reg = alloc_preg (cfg);
2837         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
2838         csig = sig_to_rgctx_sig (fsig);
2839         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
2840 }
2841
2842 /* Emit an indirect call to the function descriptor ADDR */
2843 static MonoInst*
2844 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
2845 {
2846         int addr_reg, arg_reg;
2847         MonoInst *call_target;
2848
2849         g_assert (cfg->llvm_only);
2850
2851         /*
2852          * addr points to a <addr, arg> pair, load both of them, and
2853          * make a call to addr, passing arg as an extra arg.
2854          */
2855         addr_reg = alloc_preg (cfg);
2856         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
2857         arg_reg = alloc_preg (cfg);
2858         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
2859
2860         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
2861 }
2862
2863 static gboolean
2864 direct_icalls_enabled (MonoCompile *cfg)
2865 {
2866         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
2867 #ifdef TARGET_AMD64
2868         if (cfg->compile_llvm && !cfg->llvm_only)
2869                 return FALSE;
2870 #endif
2871         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
2872                 return FALSE;
2873         return TRUE;
2874 }
2875
2876 MonoInst*
2877 mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
2878 {
2879         /*
2880          * Call the jit icall without a wrapper if possible.
2881          * The wrapper is needed for the following reasons:
2882          * - to handle exceptions thrown using mono_raise_exceptions () from the
2883          *   icall function. The EH code needs the lmf frame pushed by the
2884          *   wrapper to be able to unwind back to managed code.
2885          * - to be able to do stack walks for asynchronously suspended
2886          *   threads when debugging.
2887          */
2888         if (info->no_raise && direct_icalls_enabled (cfg)) {
2889                 char *name;
2890                 int costs;
2891
2892                 if (!info->wrapper_method) {
2893                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
2894                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
2895                         g_free (name);
2896                         mono_memory_barrier ();
2897                 }
2898
2899                 /*
2900                  * Inline the wrapper method, which is basically a call to the C icall, and
2901                  * an exception check.
2902                  */
2903                 costs = inline_method (cfg, info->wrapper_method, NULL,
2904                                                            args, NULL, il_offset, TRUE);
2905                 g_assert (costs > 0);
2906                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
2907
2908                 return args [0];
2909         } else {
2910                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2911         }
2912 }
2913  
2914 static MonoInst*
2915 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2916 {
2917         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2918                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2919                         int widen_op = -1;
2920
2921                         /* 
2922                          * Native code might return non register sized integers 
2923                          * without initializing the upper bits.
2924                          */
2925                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2926                         case OP_LOADI1_MEMBASE:
2927                                 widen_op = OP_ICONV_TO_I1;
2928                                 break;
2929                         case OP_LOADU1_MEMBASE:
2930                                 widen_op = OP_ICONV_TO_U1;
2931                                 break;
2932                         case OP_LOADI2_MEMBASE:
2933                                 widen_op = OP_ICONV_TO_I2;
2934                                 break;
2935                         case OP_LOADU2_MEMBASE:
2936                                 widen_op = OP_ICONV_TO_U2;
2937                                 break;
2938                         default:
2939                                 break;
2940                         }
2941
2942                         if (widen_op != -1) {
2943                                 int dreg = alloc_preg (cfg);
2944                                 MonoInst *widen;
2945
2946                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2947                                 widen->type = ins->type;
2948                                 ins = widen;
2949                         }
2950                 }
2951         }
2952
2953         return ins;
2954 }
2955
2956
2957 static void
2958 emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
2959 {
2960         MonoInst *args [16];
2961
2962         args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
2963         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
2964
2965         mono_emit_jit_icall (cfg, mono_throw_method_access, args);
2966 }
2967
2968 static MonoMethod*
2969 get_memcpy_method (void)
2970 {
2971         static MonoMethod *memcpy_method = NULL;
2972         if (!memcpy_method) {
2973                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2974                 if (!memcpy_method)
2975                         g_error ("Old corlib found. Install a new one");
2976         }
2977         return memcpy_method;
2978 }
2979
2980 static void
2981 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
2982 {
2983         MonoClassField *field;
2984         gpointer iter = NULL;
2985
2986         while ((field = mono_class_get_fields (klass, &iter))) {
2987                 int foffset;
2988
2989                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2990                         continue;
2991                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2992                 if (mini_type_is_reference (mono_field_get_type (field))) {
2993                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2994                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2995                 } else {
2996                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2997                         if (field_class->has_references)
2998                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
2999                 }
3000         }
3001 }
3002
3003 static void
3004 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3005 {
3006         int card_table_shift_bits;
3007         gpointer card_table_mask;
3008         guint8 *card_table;
3009         MonoInst *dummy_use;
3010         int nursery_shift_bits;
3011         size_t nursery_size;
3012
3013         if (!cfg->gen_write_barriers)
3014                 return;
3015
3016         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3017
3018         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3019
3020         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3021                 MonoInst *wbarrier;
3022
3023                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3024                 wbarrier->sreg1 = ptr->dreg;
3025                 wbarrier->sreg2 = value->dreg;
3026                 MONO_ADD_INS (cfg->cbb, wbarrier);
3027         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3028                 int offset_reg = alloc_preg (cfg);
3029                 int card_reg;
3030                 MonoInst *ins;
3031
3032                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3033                 if (card_table_mask)
3034                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3035
3036                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3037                  * IMM's larger than 32bits.
3038                  */
3039                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3040                 card_reg = ins->dreg;
3041
3042                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3043                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3044         } else {
3045                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3046                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3047         }
3048
3049         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3050 }
3051
3052 static gboolean
3053 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3054 {
3055         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3056         unsigned need_wb = 0;
3057
3058         if (align == 0)
3059                 align = 4;
3060
3061         /*types with references can't have alignment smaller than sizeof(void*) */
3062         if (align < SIZEOF_VOID_P)
3063                 return FALSE;
3064
3065         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3066         if (size > 32 * SIZEOF_VOID_P)
3067                 return FALSE;
3068
3069         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3070
3071         /* We don't unroll more than 5 stores to avoid code bloat. */
3072         if (size > 5 * SIZEOF_VOID_P) {
3073                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3074                 size += (SIZEOF_VOID_P - 1);
3075                 size &= ~(SIZEOF_VOID_P - 1);
3076
3077                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3078                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3079                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3080                 return TRUE;
3081         }
3082
3083         destreg = iargs [0]->dreg;
3084         srcreg = iargs [1]->dreg;
3085         offset = 0;
3086
3087         dest_ptr_reg = alloc_preg (cfg);
3088         tmp_reg = alloc_preg (cfg);
3089
3090         /*tmp = dreg*/
3091         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3092
3093         while (size >= SIZEOF_VOID_P) {
3094                 MonoInst *load_inst;
3095                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3096                 load_inst->dreg = tmp_reg;
3097                 load_inst->inst_basereg = srcreg;
3098                 load_inst->inst_offset = offset;
3099                 MONO_ADD_INS (cfg->cbb, load_inst);
3100
3101                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3102
3103                 if (need_wb & 0x1)
3104                         emit_write_barrier (cfg, iargs [0], load_inst);
3105
3106                 offset += SIZEOF_VOID_P;
3107                 size -= SIZEOF_VOID_P;
3108                 need_wb >>= 1;
3109
3110                 /*tmp += sizeof (void*)*/
3111                 if (size >= SIZEOF_VOID_P) {
3112                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3113                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3114                 }
3115         }
3116
3117         /* Those cannot be references since size < sizeof (void*) */
3118         while (size >= 4) {
3119                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3120                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3121                 offset += 4;
3122                 size -= 4;
3123         }
3124
3125         while (size >= 2) {
3126                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3127                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3128                 offset += 2;
3129                 size -= 2;
3130         }
3131
3132         while (size >= 1) {
3133                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3134                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3135                 offset += 1;
3136                 size -= 1;
3137         }
3138
3139         return TRUE;
3140 }
3141
3142 /*
3143  * Emit code to copy a valuetype of type @klass whose address is stored in
3144  * @src->dreg to memory whose address is stored at @dest->dreg.
3145  */
3146 void
3147 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3148 {
3149         MonoInst *iargs [4];
3150         int n;
3151         guint32 align = 0;
3152         MonoMethod *memcpy_method;
3153         MonoInst *size_ins = NULL;
3154         MonoInst *memcpy_ins = NULL;
3155
3156         g_assert (klass);
3157         if (cfg->gshared)
3158                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3159
3160         /*
3161          * This check breaks with spilled vars... need to handle it during verification anyway.
3162          * g_assert (klass && klass == src->klass && klass == dest->klass);
3163          */
3164
3165         if (mini_is_gsharedvt_klass (klass)) {
3166                 g_assert (!native);
3167                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3168                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3169         }
3170
3171         if (native)
3172                 n = mono_class_native_size (klass, &align);
3173         else
3174                 n = mono_class_value_size (klass, &align);
3175
3176         /* if native is true there should be no references in the struct */
3177         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3178                 /* Avoid barriers when storing to the stack */
3179                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3180                           (dest->opcode == OP_LDADDR))) {
3181                         int context_used;
3182
3183                         iargs [0] = dest;
3184                         iargs [1] = src;
3185
3186                         context_used = mini_class_check_context_used (cfg, klass);
3187
3188                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3189                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3190                                 return;
3191                         } else if (context_used) {
3192                                 iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3193                         }  else {
3194                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3195                                 if (!cfg->compile_aot)
3196                                         mono_class_compute_gc_descriptor (klass);
3197                         }
3198
3199                         if (size_ins)
3200                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3201                         else
3202                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3203                         return;
3204                 }
3205         }
3206
3207         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3208                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3209                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3210         } else {
3211                 iargs [0] = dest;
3212                 iargs [1] = src;
3213                 if (size_ins)
3214                         iargs [2] = size_ins;
3215                 else
3216                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3217                 
3218                 memcpy_method = get_memcpy_method ();
3219                 if (memcpy_ins)
3220                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3221                 else
3222                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3223         }
3224 }
3225
3226 static MonoMethod*
3227 get_memset_method (void)
3228 {
3229         static MonoMethod *memset_method = NULL;
3230         if (!memset_method) {
3231                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3232                 if (!memset_method)
3233                         g_error ("Old corlib found. Install a new one");
3234         }
3235         return memset_method;
3236 }
3237
3238 void
3239 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3240 {
3241         MonoInst *iargs [3];
3242         int n;
3243         guint32 align;
3244         MonoMethod *memset_method;
3245         MonoInst *size_ins = NULL;
3246         MonoInst *bzero_ins = NULL;
3247         static MonoMethod *bzero_method;
3248
3249         /* FIXME: Optimize this for the case when dest is an LDADDR */
3250         mono_class_init (klass);
3251         if (mini_is_gsharedvt_klass (klass)) {
3252                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3253                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3254                 if (!bzero_method)
3255                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3256                 g_assert (bzero_method);
3257                 iargs [0] = dest;
3258                 iargs [1] = size_ins;
3259                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3260                 return;
3261         }
3262
3263         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3264
3265         n = mono_class_value_size (klass, &align);
3266
3267         if (n <= sizeof (gpointer) * 8) {
3268                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3269         }
3270         else {
3271                 memset_method = get_memset_method ();
3272                 iargs [0] = dest;
3273                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3274                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3275                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3276         }
3277 }
3278
3279 /*
3280  * emit_get_rgctx:
3281  *
3282  *   Emit IR to return either the this pointer for instance method,
3283  * or the mrgctx for static methods.
3284  */
3285 static MonoInst*
3286 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3287 {
3288         MonoInst *this_ins = NULL;
3289
3290         g_assert (cfg->gshared);
3291
3292         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3293                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3294                 !method->klass->valuetype)
3295                 EMIT_NEW_VARLOAD (cfg, this_ins, cfg->this_arg, &mono_defaults.object_class->byval_arg);
3296
3297         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3298                 MonoInst *mrgctx_loc, *mrgctx_var;
3299
3300                 g_assert (!this_ins);
3301                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3302
3303                 mrgctx_loc = mono_get_vtable_var (cfg);
3304                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3305
3306                 return mrgctx_var;
3307         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3308                 MonoInst *vtable_loc, *vtable_var;
3309
3310                 g_assert (!this_ins);
3311
3312                 vtable_loc = mono_get_vtable_var (cfg);
3313                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3314
3315                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3316                         MonoInst *mrgctx_var = vtable_var;
3317                         int vtable_reg;
3318
3319                         vtable_reg = alloc_preg (cfg);
3320                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3321                         vtable_var->type = STACK_PTR;
3322                 }
3323
3324                 return vtable_var;
3325         } else {
3326                 MonoInst *ins;
3327                 int vtable_reg;
3328         
3329                 vtable_reg = alloc_preg (cfg);
3330                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3331                 return ins;
3332         }
3333 }
3334
3335 static MonoJumpInfoRgctxEntry *
3336 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3337 {
3338         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3339         res->method = method;
3340         res->in_mrgctx = in_mrgctx;
3341         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3342         res->data->type = patch_type;
3343         res->data->data.target = patch_data;
3344         res->info_type = info_type;
3345
3346         return res;
3347 }
3348
3349 static inline MonoInst*
3350 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3351 {
3352         MonoInst *args [16];
3353         MonoInst *call;
3354
3355         // FIXME: No fastpath since the slot is not a compile time constant
3356         args [0] = rgctx;
3357         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3358         if (entry->in_mrgctx)
3359                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3360         else
3361                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3362         return call;
3363 #if 0
3364         /*
3365          * FIXME: This can be called during decompose, which is a problem since it creates
3366          * new bblocks.
3367          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3368          */
3369         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3370         gboolean mrgctx;
3371         MonoBasicBlock *is_null_bb, *end_bb;
3372         MonoInst *res, *ins, *call;
3373         MonoInst *args[16];
3374
3375         slot = mini_get_rgctx_entry_slot (entry);
3376
3377         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3378         index = MONO_RGCTX_SLOT_INDEX (slot);
3379         if (mrgctx)
3380                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3381         for (depth = 0; ; ++depth) {
3382                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3383
3384                 if (index < size - 1)
3385                         break;
3386                 index -= size - 1;
3387         }
3388
3389         NEW_BBLOCK (cfg, end_bb);
3390         NEW_BBLOCK (cfg, is_null_bb);
3391
3392         if (mrgctx) {
3393                 rgctx_reg = rgctx->dreg;
3394         } else {
3395                 rgctx_reg = alloc_preg (cfg);
3396
3397                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3398                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3399                 NEW_BBLOCK (cfg, is_null_bb);
3400
3401                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3402                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3403         }
3404
3405         for (i = 0; i < depth; ++i) {
3406                 int array_reg = alloc_preg (cfg);
3407
3408                 /* load ptr to next array */
3409                 if (mrgctx && i == 0)
3410                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3411                 else
3412                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3413                 rgctx_reg = array_reg;
3414                 /* is the ptr null? */
3415                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3416                 /* if yes, jump to actual trampoline */
3417                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3418         }
3419
3420         /* fetch slot */
3421         val_reg = alloc_preg (cfg);
3422         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3423         /* is the slot null? */
3424         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3425         /* if yes, jump to actual trampoline */
3426         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3427
3428         /* Fastpath */
3429         res_reg = alloc_preg (cfg);
3430         MONO_INST_NEW (cfg, ins, OP_MOVE);
3431         ins->dreg = res_reg;
3432         ins->sreg1 = val_reg;
3433         MONO_ADD_INS (cfg->cbb, ins);
3434         res = ins;
3435         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3436
3437         /* Slowpath */
3438         MONO_START_BB (cfg, is_null_bb);
3439         args [0] = rgctx;
3440         EMIT_NEW_ICONST (cfg, args [1], index);
3441         if (mrgctx)
3442                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3443         else
3444                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3445         MONO_INST_NEW (cfg, ins, OP_MOVE);
3446         ins->dreg = res_reg;
3447         ins->sreg1 = call->dreg;
3448         MONO_ADD_INS (cfg->cbb, ins);
3449         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3450
3451         MONO_START_BB (cfg, end_bb);
3452
3453         return res;
3454 #endif
3455 }
3456
3457 /*
3458  * emit_rgctx_fetch:
3459  *
3460  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3461  * given by RGCTX.
3462  */
3463 static inline MonoInst*
3464 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3465 {
3466         if (cfg->llvm_only)
3467                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3468         else
3469                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3470 }
3471
3472 MonoInst*
3473 mini_emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3474                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3475 {
3476         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);
3477         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3478
3479         return emit_rgctx_fetch (cfg, rgctx, entry);
3480 }
3481
3482 static MonoInst*
3483 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3484                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3485 {
3486         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);
3487         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3488
3489         return emit_rgctx_fetch (cfg, rgctx, entry);
3490 }
3491
3492 static MonoInst*
3493 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3494                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3495 {
3496         MonoJumpInfoGSharedVtCall *call_info;
3497         MonoJumpInfoRgctxEntry *entry;
3498         MonoInst *rgctx;
3499
3500         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3501         call_info->sig = sig;
3502         call_info->method = cmethod;
3503
3504         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);
3505         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3506
3507         return emit_rgctx_fetch (cfg, rgctx, entry);
3508 }
3509
3510 /*
3511  * emit_get_rgctx_virt_method:
3512  *
3513  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3514  */
3515 static MonoInst*
3516 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3517                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3518 {
3519         MonoJumpInfoVirtMethod *info;
3520         MonoJumpInfoRgctxEntry *entry;
3521         MonoInst *rgctx;
3522
3523         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3524         info->klass = klass;
3525         info->method = virt_method;
3526
3527         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);
3528         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3529
3530         return emit_rgctx_fetch (cfg, rgctx, entry);
3531 }
3532
3533 static MonoInst*
3534 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3535                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3536 {
3537         MonoJumpInfoRgctxEntry *entry;
3538         MonoInst *rgctx;
3539
3540         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);
3541         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3542
3543         return emit_rgctx_fetch (cfg, rgctx, entry);
3544 }
3545
3546 /*
3547  * emit_get_rgctx_method:
3548  *
3549  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3550  * normal constants, else emit a load from the rgctx.
3551  */
3552 static MonoInst*
3553 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3554                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3555 {
3556         if (!context_used) {
3557                 MonoInst *ins;
3558
3559                 switch (rgctx_type) {
3560                 case MONO_RGCTX_INFO_METHOD:
3561                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3562                         return ins;
3563                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3564                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3565                         return ins;
3566                 default:
3567                         g_assert_not_reached ();
3568                 }
3569         } else {
3570                 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);
3571                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3572
3573                 return emit_rgctx_fetch (cfg, rgctx, entry);
3574         }
3575 }
3576
3577 static MonoInst*
3578 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3579                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3580 {
3581         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);
3582         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3583
3584         return emit_rgctx_fetch (cfg, rgctx, entry);
3585 }
3586
3587 static int
3588 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3589 {
3590         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3591         MonoRuntimeGenericContextInfoTemplate *template_;
3592         int i, idx;
3593
3594         g_assert (info);
3595
3596         for (i = 0; i < info->num_entries; ++i) {
3597                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3598
3599                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3600                         return i;
3601         }
3602
3603         if (info->num_entries == info->count_entries) {
3604                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3605                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3606
3607                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3608
3609                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3610                 info->entries = new_entries;
3611                 info->count_entries = new_count_entries;
3612         }
3613
3614         idx = info->num_entries;
3615         template_ = &info->entries [idx];
3616         template_->info_type = rgctx_type;
3617         template_->data = data;
3618
3619         info->num_entries ++;
3620
3621         return idx;
3622 }
3623
3624 /*
3625  * emit_get_gsharedvt_info:
3626  *
3627  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3628  */
3629 static MonoInst*
3630 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3631 {
3632         MonoInst *ins;
3633         int idx, dreg;
3634
3635         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3636         /* Load info->entries [idx] */
3637         dreg = alloc_preg (cfg);
3638         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3639
3640         return ins;
3641 }
3642
3643 static MonoInst*
3644 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3645 {
3646         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3647 }
3648
3649 /*
3650  * On return the caller must check @klass for load errors.
3651  */
3652 static void
3653 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3654 {
3655         MonoInst *vtable_arg;
3656         int context_used;
3657
3658         context_used = mini_class_check_context_used (cfg, klass);
3659
3660         if (context_used) {
3661                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
3662                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3663         } else {
3664                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3665
3666                 if (!vtable)
3667                         return;
3668                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3669         }
3670
3671         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3672                 MonoInst *ins;
3673
3674                 /*
3675                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3676                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3677                  */
3678                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3679                 ins->sreg1 = vtable_arg->dreg;
3680                 MONO_ADD_INS (cfg->cbb, ins);
3681         } else {
3682                 int inited_reg;
3683                 MonoBasicBlock *inited_bb;
3684                 MonoInst *args [16];
3685
3686                 inited_reg = alloc_ireg (cfg);
3687
3688                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, inited_reg, vtable_arg->dreg, MONO_STRUCT_OFFSET (MonoVTable, initialized));
3689
3690                 NEW_BBLOCK (cfg, inited_bb);
3691
3692                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3693                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3694
3695                 args [0] = vtable_arg;
3696                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3697
3698                 MONO_START_BB (cfg, inited_bb);
3699         }
3700 }
3701
3702 static void
3703 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3704 {
3705         MonoInst *ins;
3706
3707         if (cfg->gen_seq_points && cfg->method == method) {
3708                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3709                 if (nonempty_stack)
3710                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3711                 MONO_ADD_INS (cfg->cbb, ins);
3712         }
3713 }
3714
3715 void
3716 mini_save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3717 {
3718         if (mini_get_debug_options ()->better_cast_details) {
3719                 int vtable_reg = alloc_preg (cfg);
3720                 int klass_reg = alloc_preg (cfg);
3721                 MonoBasicBlock *is_null_bb = NULL;
3722                 MonoInst *tls_get;
3723                 int to_klass_reg, context_used;
3724
3725                 if (null_check) {
3726                         NEW_BBLOCK (cfg, is_null_bb);
3727
3728                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3729                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3730                 }
3731
3732                 tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
3733                 if (!tls_get) {
3734                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3735                         exit (1);
3736                 }
3737
3738                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3739                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3740
3741                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3742
3743                 context_used = mini_class_check_context_used (cfg, klass);
3744                 if (context_used) {
3745                         MonoInst *class_ins;
3746
3747                         class_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3748                         to_klass_reg = class_ins->dreg;
3749                 } else {
3750                         to_klass_reg = alloc_preg (cfg);
3751                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3752                 }
3753                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3754
3755                 if (null_check)
3756                         MONO_START_BB (cfg, is_null_bb);
3757         }
3758 }
3759
3760 void
3761 mini_reset_cast_details (MonoCompile *cfg)
3762 {
3763         /* Reset the variables holding the cast details */
3764         if (mini_get_debug_options ()->better_cast_details) {
3765                 MonoInst *tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
3766                 /* It is enough to reset the from field */
3767                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3768         }
3769 }
3770
3771 /*
3772  * On return the caller must check @array_class for load errors
3773  */
3774 static void
3775 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3776 {
3777         int vtable_reg = alloc_preg (cfg);
3778         int context_used;
3779
3780         context_used = mini_class_check_context_used (cfg, array_class);
3781
3782         mini_save_cast_details (cfg, array_class, obj->dreg, FALSE);
3783
3784         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3785
3786         if (cfg->opt & MONO_OPT_SHARED) {
3787                 int class_reg = alloc_preg (cfg);
3788                 MonoInst *ins;
3789
3790                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3791                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3792                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3793         } else if (context_used) {
3794                 MonoInst *vtable_ins;
3795
3796                 vtable_ins = mini_emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3797                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3798         } else {
3799                 if (cfg->compile_aot) {
3800                         int vt_reg;
3801                         MonoVTable *vtable;
3802
3803                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3804                                 return;
3805                         vt_reg = alloc_preg (cfg);
3806                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3807                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3808                 } else {
3809                         MonoVTable *vtable;
3810                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3811                                 return;
3812                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3813                 }
3814         }
3815         
3816         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3817
3818         mini_reset_cast_details (cfg);
3819 }
3820
3821 /**
3822  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3823  * generic code is generated.
3824  */
3825 static MonoInst*
3826 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3827 {
3828         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3829
3830         if (context_used) {
3831                 MonoInst *rgctx, *addr;
3832
3833                 /* FIXME: What if the class is shared?  We might not
3834                    have to get the address of the method from the
3835                    RGCTX. */
3836                 addr = emit_get_rgctx_method (cfg, context_used, method,
3837                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3838                 if (cfg->llvm_only) {
3839                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
3840                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
3841                 } else {
3842                         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3843
3844                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3845                 }
3846         } else {
3847                 gboolean pass_vtable, pass_mrgctx;
3848                 MonoInst *rgctx_arg = NULL;
3849
3850                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3851                 g_assert (!pass_mrgctx);
3852
3853                 if (pass_vtable) {
3854                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3855
3856                         g_assert (vtable);
3857                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3858                 }
3859
3860                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3861         }
3862 }
3863
3864 static MonoInst*
3865 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3866 {
3867         MonoInst *add;
3868         int obj_reg;
3869         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3870         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3871         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3872         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3873
3874         obj_reg = sp [0]->dreg;
3875         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3876         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3877
3878         /* FIXME: generics */
3879         g_assert (klass->rank == 0);
3880                         
3881         // Check rank == 0
3882         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3883         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3884
3885         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3886         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3887
3888         if (context_used) {
3889                 MonoInst *element_class;
3890
3891                 /* This assertion is from the unboxcast insn */
3892                 g_assert (klass->rank == 0);
3893
3894                 element_class = mini_emit_get_rgctx_klass (cfg, context_used,
3895                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
3896
3897                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3898                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3899         } else {
3900                 mini_save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
3901                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3902                 mini_reset_cast_details (cfg);
3903         }
3904
3905         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3906         MONO_ADD_INS (cfg->cbb, add);
3907         add->type = STACK_MP;
3908         add->klass = klass;
3909
3910         return add;
3911 }
3912
3913 static MonoInst*
3914 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
3915 {
3916         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3917         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3918         MonoInst *ins;
3919         int dreg, addr_reg;
3920
3921         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3922
3923         /* obj */
3924         args [0] = obj;
3925
3926         /* klass */
3927         args [1] = klass_inst;
3928
3929         /* CASTCLASS */
3930         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3931
3932         NEW_BBLOCK (cfg, is_ref_bb);
3933         NEW_BBLOCK (cfg, is_nullable_bb);
3934         NEW_BBLOCK (cfg, end_bb);
3935         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3936         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
3937         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3938
3939         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
3940         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3941
3942         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3943         addr_reg = alloc_dreg (cfg, STACK_MP);
3944
3945         /* Non-ref case */
3946         /* UNBOX */
3947         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3948         MONO_ADD_INS (cfg->cbb, addr);
3949
3950         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3951
3952         /* Ref case */
3953         MONO_START_BB (cfg, is_ref_bb);
3954
3955         /* Save the ref to a temporary */
3956         dreg = alloc_ireg (cfg);
3957         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3958         addr->dreg = addr_reg;
3959         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3960         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3961
3962         /* Nullable case */
3963         MONO_START_BB (cfg, is_nullable_bb);
3964
3965         {
3966                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3967                 MonoInst *unbox_call;
3968                 MonoMethodSignature *unbox_sig;
3969
3970                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3971                 unbox_sig->ret = &klass->byval_arg;
3972                 unbox_sig->param_count = 1;
3973                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3974
3975                 if (cfg->llvm_only)
3976                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
3977                 else
3978                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3979
3980                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3981                 addr->dreg = addr_reg;
3982         }
3983
3984         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3985
3986         /* End */
3987         MONO_START_BB (cfg, end_bb);
3988
3989         /* LDOBJ */
3990         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3991
3992         return ins;
3993 }
3994
3995 /*
3996  * Returns NULL and set the cfg exception on error.
3997  */
3998 static MonoInst*
3999 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4000 {
4001         MonoInst *iargs [2];
4002         void *alloc_ftn;
4003
4004         if (context_used) {
4005                 MonoInst *data;
4006                 MonoRgctxInfoType rgctx_info;
4007                 MonoInst *iargs [2];
4008                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4009
4010                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4011
4012                 if (cfg->opt & MONO_OPT_SHARED)
4013                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4014                 else
4015                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4016                 data = mini_emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4017
4018                 if (cfg->opt & MONO_OPT_SHARED) {
4019                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4020                         iargs [1] = data;
4021                         alloc_ftn = ves_icall_object_new;
4022                 } else {
4023                         iargs [0] = data;
4024                         alloc_ftn = ves_icall_object_new_specific;
4025                 }
4026
4027                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4028                         if (known_instance_size) {
4029                                 int size = mono_class_instance_size (klass);
4030                                 if (size < sizeof (MonoObject))
4031                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4032
4033                                 EMIT_NEW_ICONST (cfg, iargs [1], size);
4034                         }
4035                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4036                 }
4037
4038                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4039         }
4040
4041         if (cfg->opt & MONO_OPT_SHARED) {
4042                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4043                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4044
4045                 alloc_ftn = ves_icall_object_new;
4046         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !mono_class_is_ginst (klass)) {
4047                 /* This happens often in argument checking code, eg. throw new FooException... */
4048                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4049                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4050                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4051         } else {
4052                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4053                 MonoMethod *managed_alloc = NULL;
4054                 gboolean pass_lw;
4055
4056                 if (!vtable) {
4057                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4058                         cfg->exception_ptr = klass;
4059                         return NULL;
4060                 }
4061
4062                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4063
4064                 if (managed_alloc) {
4065                         int size = mono_class_instance_size (klass);
4066                         if (size < sizeof (MonoObject))
4067                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4068
4069                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4070                         EMIT_NEW_ICONST (cfg, iargs [1], size);
4071                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4072                 }
4073                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4074                 if (pass_lw) {
4075                         guint32 lw = vtable->klass->instance_size;
4076                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4077                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4078                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4079                 }
4080                 else {
4081                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4082                 }
4083         }
4084
4085         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4086 }
4087         
4088 /*
4089  * Returns NULL and set the cfg exception on error.
4090  */     
4091 static MonoInst*
4092 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4093 {
4094         MonoInst *alloc, *ins;
4095
4096         if (mono_class_is_nullable (klass)) {
4097                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4098
4099                 if (context_used) {
4100                         if (cfg->llvm_only && cfg->gsharedvt) {
4101                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4102                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4103                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4104                         } else {
4105                                 /* FIXME: What if the class is shared?  We might not
4106                                    have to get the method address from the RGCTX. */
4107                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4108                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4109                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
4110
4111                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4112                         }
4113                 } else {
4114                         gboolean pass_vtable, pass_mrgctx;
4115                         MonoInst *rgctx_arg = NULL;
4116
4117                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4118                         g_assert (!pass_mrgctx);
4119
4120                         if (pass_vtable) {
4121                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4122
4123                                 g_assert (vtable);
4124                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4125                         }
4126
4127                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4128                 }
4129         }
4130
4131         if (mini_is_gsharedvt_klass (klass)) {
4132                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4133                 MonoInst *res, *is_ref, *src_var, *addr;
4134                 int dreg;
4135
4136                 dreg = alloc_ireg (cfg);
4137
4138                 NEW_BBLOCK (cfg, is_ref_bb);
4139                 NEW_BBLOCK (cfg, is_nullable_bb);
4140                 NEW_BBLOCK (cfg, end_bb);
4141                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4142                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4143                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4144
4145                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4146                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4147
4148                 /* Non-ref case */
4149                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4150                 if (!alloc)
4151                         return NULL;
4152                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4153                 ins->opcode = OP_STOREV_MEMBASE;
4154
4155                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4156                 res->type = STACK_OBJ;
4157                 res->klass = klass;
4158                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4159                 
4160                 /* Ref case */
4161                 MONO_START_BB (cfg, is_ref_bb);
4162
4163                 /* val is a vtype, so has to load the value manually */
4164                 src_var = get_vreg_to_inst (cfg, val->dreg);
4165                 if (!src_var)
4166                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4167                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4168                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4169                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4170
4171                 /* Nullable case */
4172                 MONO_START_BB (cfg, is_nullable_bb);
4173
4174                 {
4175                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4176                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4177                         MonoInst *box_call;
4178                         MonoMethodSignature *box_sig;
4179
4180                         /*
4181                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4182                          * construct that method at JIT time, so have to do things by hand.
4183                          */
4184                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4185                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4186                         box_sig->param_count = 1;
4187                         box_sig->params [0] = &klass->byval_arg;
4188
4189                         if (cfg->llvm_only)
4190                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4191                         else
4192                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4193                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4194                         res->type = STACK_OBJ;
4195                         res->klass = klass;
4196                 }
4197
4198                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4199
4200                 MONO_START_BB (cfg, end_bb);
4201
4202                 return res;
4203         } else {
4204                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4205                 if (!alloc)
4206                         return NULL;
4207
4208                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4209                 return alloc;
4210         }
4211 }
4212
4213 static GHashTable* direct_icall_type_hash;
4214
4215 static gboolean
4216 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4217 {
4218         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4219         if (!direct_icalls_enabled (cfg))
4220                 return FALSE;
4221
4222         /*
4223          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4224          * Whitelist a few icalls for now.
4225          */
4226         if (!direct_icall_type_hash) {
4227                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4228
4229                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4230                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4231                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4232                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4233                 mono_memory_barrier ();
4234                 direct_icall_type_hash = h;
4235         }
4236
4237         if (cmethod->klass == mono_defaults.math_class)
4238                 return TRUE;
4239         /* No locking needed */
4240         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4241                 return TRUE;
4242         return FALSE;
4243 }
4244
4245 static gboolean
4246 method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
4247 {
4248         if (cmethod->klass == mono_defaults.systemtype_class) {
4249                 if (!strcmp (cmethod->name, "GetType"))
4250                         return TRUE;
4251         }
4252         return FALSE;
4253 }
4254
4255 static G_GNUC_UNUSED MonoInst*
4256 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4257 {
4258         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4259         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4260         gboolean is_i4;
4261
4262         switch (enum_type->type) {
4263         case MONO_TYPE_I8:
4264         case MONO_TYPE_U8:
4265 #if SIZEOF_REGISTER == 8
4266         case MONO_TYPE_I:
4267         case MONO_TYPE_U:
4268 #endif
4269                 is_i4 = FALSE;
4270                 break;
4271         default:
4272                 is_i4 = TRUE;
4273                 break;
4274         }
4275
4276         {
4277                 MonoInst *load, *and_, *cmp, *ceq;
4278                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4279                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4280                 int dest_reg = alloc_ireg (cfg);
4281
4282                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4283                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4284                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4285                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4286
4287                 ceq->type = STACK_I4;
4288
4289                 if (!is_i4) {
4290                         load = mono_decompose_opcode (cfg, load);
4291                         and_ = mono_decompose_opcode (cfg, and_);
4292                         cmp = mono_decompose_opcode (cfg, cmp);
4293                         ceq = mono_decompose_opcode (cfg, ceq);
4294                 }
4295
4296                 return ceq;
4297         }
4298 }
4299
4300 /*
4301  * Returns NULL and set the cfg exception on error.
4302  */
4303 static G_GNUC_UNUSED MonoInst*
4304 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
4305 {
4306         MonoInst *ptr;
4307         int dreg;
4308         gpointer trampoline;
4309         MonoInst *obj, *method_ins, *tramp_ins;
4310         MonoDomain *domain;
4311         guint8 **code_slot;
4312
4313         if (virtual_ && !cfg->llvm_only) {
4314                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4315                 g_assert (invoke);
4316
4317                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4318                         return NULL;
4319         }
4320
4321         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
4322         if (!obj)
4323                 return NULL;
4324
4325         /* Inline the contents of mono_delegate_ctor */
4326
4327         /* Set target field */
4328         /* Optimize away setting of NULL target */
4329         if (!MONO_INS_IS_PCONST_NULL (target)) {
4330                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4331                 if (cfg->gen_write_barriers) {
4332                         dreg = alloc_preg (cfg);
4333                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4334                         emit_write_barrier (cfg, ptr, target);
4335                 }
4336         }
4337
4338         /* Set method field */
4339         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4340         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4341
4342         /* 
4343          * To avoid looking up the compiled code belonging to the target method
4344          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4345          * store it, and we fill it after the method has been compiled.
4346          */
4347         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4348                 MonoInst *code_slot_ins;
4349
4350                 if (context_used) {
4351                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4352                 } else {
4353                         domain = mono_domain_get ();
4354                         mono_domain_lock (domain);
4355                         if (!domain_jit_info (domain)->method_code_hash)
4356                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4357                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4358                         if (!code_slot) {
4359                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
4360                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4361                         }
4362                         mono_domain_unlock (domain);
4363
4364                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4365                 }
4366                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4367         }
4368
4369         if (cfg->llvm_only) {
4370                 MonoInst *args [16];
4371
4372                 if (virtual_) {
4373                         args [0] = obj;
4374                         args [1] = target;
4375                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4376                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
4377                 } else {
4378                         args [0] = obj;
4379                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
4380                 }
4381
4382                 return obj;
4383         }
4384
4385         if (cfg->compile_aot) {
4386                 MonoDelegateClassMethodPair *del_tramp;
4387
4388                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4389                 del_tramp->klass = klass;
4390                 del_tramp->method = context_used ? NULL : method;
4391                 del_tramp->is_virtual = virtual_;
4392                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4393         } else {
4394                 if (virtual_)
4395                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4396                 else
4397                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4398                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4399         }
4400
4401         /* Set invoke_impl field */
4402         if (virtual_) {
4403                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4404         } else {
4405                 dreg = alloc_preg (cfg);
4406                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4407                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4408
4409                 dreg = alloc_preg (cfg);
4410                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4411                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4412         }
4413
4414         dreg = alloc_preg (cfg);
4415         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
4416         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
4417
4418         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4419
4420         return obj;
4421 }
4422
4423 static MonoInst*
4424 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4425 {
4426         MonoJitICallInfo *info;
4427
4428         /* Need to register the icall so it gets an icall wrapper */
4429         info = mono_get_array_new_va_icall (rank);
4430
4431         cfg->flags |= MONO_CFG_HAS_VARARGS;
4432
4433         /* mono_array_new_va () needs a vararg calling convention */
4434         cfg->exception_message = g_strdup ("array-new");
4435         cfg->disable_llvm = TRUE;
4436
4437         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4438         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4439 }
4440
4441 /*
4442  * handle_constrained_gsharedvt_call:
4443  *
4444  *   Handle constrained calls where the receiver is a gsharedvt type.
4445  * Return the instruction representing the call. Set the cfg exception on failure.
4446  */
4447 static MonoInst*
4448 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
4449                                                                    gboolean *ref_emit_widen)
4450 {
4451         MonoInst *ins = NULL;
4452         gboolean emit_widen = *ref_emit_widen;
4453
4454         /*
4455          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
4456          * 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
4457          * pack the arguments into an array, and do the rest of the work in in an icall.
4458          */
4459         if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
4460                 (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mini_is_gsharedvt_type (fsig->ret)) &&
4461                 (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]))))) {
4462                 MonoInst *args [16];
4463
4464                 /*
4465                  * This case handles calls to
4466                  * - object:ToString()/Equals()/GetHashCode(),
4467                  * - System.IComparable<T>:CompareTo()
4468                  * - System.IEquatable<T>:Equals ()
4469                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
4470                  */
4471
4472                 args [0] = sp [0];
4473                 if (mono_method_check_context_used (cmethod))
4474                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
4475                 else
4476                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
4477                 args [2] = mini_emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
4478
4479                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
4480                 if (fsig->hasthis && fsig->param_count) {
4481                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
4482                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
4483                         ins->dreg = alloc_preg (cfg);
4484                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
4485                         MONO_ADD_INS (cfg->cbb, ins);
4486                         args [4] = ins;
4487
4488                         if (mini_is_gsharedvt_type (fsig->params [0])) {
4489                                 int addr_reg, deref_arg_reg;
4490
4491                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4492                                 deref_arg_reg = alloc_preg (cfg);
4493                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
4494                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
4495
4496                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
4497                                 addr_reg = ins->dreg;
4498                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
4499                         } else {
4500                                 EMIT_NEW_ICONST (cfg, args [3], 0);
4501                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
4502                         }
4503                 } else {
4504                         EMIT_NEW_ICONST (cfg, args [3], 0);
4505                         EMIT_NEW_ICONST (cfg, args [4], 0);
4506                 }
4507                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
4508                 emit_widen = FALSE;
4509
4510                 if (mini_is_gsharedvt_type (fsig->ret)) {
4511                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
4512                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
4513                         MonoInst *add;
4514
4515                         /* Unbox */
4516                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
4517                         MONO_ADD_INS (cfg->cbb, add);
4518                         /* Load value */
4519                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
4520                         MONO_ADD_INS (cfg->cbb, ins);
4521                         /* ins represents the call result */
4522                 }
4523         } else {
4524                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
4525         }
4526
4527         *ref_emit_widen = emit_widen;
4528
4529         return ins;
4530
4531  exception_exit:
4532         return NULL;
4533 }
4534
4535 static void
4536 mono_emit_load_got_addr (MonoCompile *cfg)
4537 {
4538         MonoInst *getaddr, *dummy_use;
4539
4540         if (!cfg->got_var || cfg->got_var_allocated)
4541                 return;
4542
4543         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4544         getaddr->cil_code = cfg->header->code;
4545         getaddr->dreg = cfg->got_var->dreg;
4546
4547         /* Add it to the start of the first bblock */
4548         if (cfg->bb_entry->code) {
4549                 getaddr->next = cfg->bb_entry->code;
4550                 cfg->bb_entry->code = getaddr;
4551         }
4552         else
4553                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4554
4555         cfg->got_var_allocated = TRUE;
4556
4557         /* 
4558          * Add a dummy use to keep the got_var alive, since real uses might
4559          * only be generated by the back ends.
4560          * Add it to end_bblock, so the variable's lifetime covers the whole
4561          * method.
4562          * It would be better to make the usage of the got var explicit in all
4563          * cases when the backend needs it (i.e. calls, throw etc.), so this
4564          * wouldn't be needed.
4565          */
4566         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4567         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4568 }
4569
4570 static int inline_limit;
4571 static gboolean inline_limit_inited;
4572
4573 static gboolean
4574 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4575 {
4576         MonoMethodHeaderSummary header;
4577         MonoVTable *vtable;
4578 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4579         MonoMethodSignature *sig = mono_method_signature (method);
4580         int i;
4581 #endif
4582
4583         if (cfg->disable_inline)
4584                 return FALSE;
4585         if (cfg->gsharedvt)
4586                 return FALSE;
4587
4588         if (cfg->inline_depth > 10)
4589                 return FALSE;
4590
4591         if (!mono_method_get_header_summary (method, &header))
4592                 return FALSE;
4593
4594         /*runtime, icall and pinvoke are checked by summary call*/
4595         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4596             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4597             (mono_class_is_marshalbyref (method->klass)) ||
4598             header.has_clauses)
4599                 return FALSE;
4600
4601         /* also consider num_locals? */
4602         /* Do the size check early to avoid creating vtables */
4603         if (!inline_limit_inited) {
4604                 if (g_getenv ("MONO_INLINELIMIT"))
4605                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4606                 else
4607                         inline_limit = INLINE_LENGTH_LIMIT;
4608                 inline_limit_inited = TRUE;
4609         }
4610         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4611                 return FALSE;
4612
4613         /*
4614          * if we can initialize the class of the method right away, we do,
4615          * otherwise we don't allow inlining if the class needs initialization,
4616          * since it would mean inserting a call to mono_runtime_class_init()
4617          * inside the inlined code
4618          */
4619         if (cfg->gshared && method->klass->has_cctor && mini_class_check_context_used (cfg, method->klass))
4620                 return FALSE;
4621
4622         if (!(cfg->opt & MONO_OPT_SHARED)) {
4623                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4624                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4625                         if (method->klass->has_cctor) {
4626                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4627                                 if (!vtable)
4628                                         return FALSE;
4629                                 if (!cfg->compile_aot) {
4630                                         MonoError error;
4631                                         if (!mono_runtime_class_init_full (vtable, &error)) {
4632                                                 mono_error_cleanup (&error);
4633                                                 return FALSE;
4634                                         }
4635                                 }
4636                         }
4637                 } else if (mono_class_is_before_field_init (method->klass)) {
4638                         if (cfg->run_cctors && method->klass->has_cctor) {
4639                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4640                                 if (!method->klass->runtime_info)
4641                                         /* No vtable created yet */
4642                                         return FALSE;
4643                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4644                                 if (!vtable)
4645                                         return FALSE;
4646                                 /* This makes so that inline cannot trigger */
4647                                 /* .cctors: too many apps depend on them */
4648                                 /* running with a specific order... */
4649                                 if (! vtable->initialized)
4650                                         return FALSE;
4651                                 MonoError error;
4652                                 if (!mono_runtime_class_init_full (vtable, &error)) {
4653                                         mono_error_cleanup (&error);
4654                                         return FALSE;
4655                                 }
4656                         }
4657                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4658                         if (!method->klass->runtime_info)
4659                                 /* No vtable created yet */
4660                                 return FALSE;
4661                         vtable = mono_class_vtable (cfg->domain, method->klass);
4662                         if (!vtable)
4663                                 return FALSE;
4664                         if (!vtable->initialized)
4665                                 return FALSE;
4666                 }
4667         } else {
4668                 /* 
4669                  * If we're compiling for shared code
4670                  * the cctor will need to be run at aot method load time, for example,
4671                  * or at the end of the compilation of the inlining method.
4672                  */
4673                 if (mono_class_needs_cctor_run (method->klass, NULL) && !mono_class_is_before_field_init (method->klass))
4674                         return FALSE;
4675         }
4676
4677 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4678         if (mono_arch_is_soft_float ()) {
4679                 /* FIXME: */
4680                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4681                         return FALSE;
4682                 for (i = 0; i < sig->param_count; ++i)
4683                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4684                                 return FALSE;
4685         }
4686 #endif
4687
4688         if (g_list_find (cfg->dont_inline, method))
4689                 return FALSE;
4690
4691         return TRUE;
4692 }
4693
4694 static gboolean
4695 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4696 {
4697         if (!cfg->compile_aot) {
4698                 g_assert (vtable);
4699                 if (vtable->initialized)
4700                         return FALSE;
4701         }
4702
4703         if (mono_class_is_before_field_init (klass)) {
4704                 if (cfg->method == method)
4705                         return FALSE;
4706         }
4707
4708         if (!mono_class_needs_cctor_run (klass, method))
4709                 return FALSE;
4710
4711         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4712                 /* The initialization is already done before the method is called */
4713                 return FALSE;
4714
4715         return TRUE;
4716 }
4717
4718 MonoInst*
4719 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4720 {
4721         MonoInst *ins;
4722         guint32 size;
4723         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4724         int context_used;
4725
4726         if (mini_is_gsharedvt_variable_klass (klass)) {
4727                 size = -1;
4728         } else {
4729                 mono_class_init (klass);
4730                 size = mono_class_array_element_size (klass);
4731         }
4732
4733         mult_reg = alloc_preg (cfg);
4734         array_reg = arr->dreg;
4735         index_reg = index->dreg;
4736
4737 #if SIZEOF_REGISTER == 8
4738         /* The array reg is 64 bits but the index reg is only 32 */
4739         if (COMPILE_LLVM (cfg)) {
4740                 /* Not needed */
4741                 index2_reg = index_reg;
4742         } else {
4743                 index2_reg = alloc_preg (cfg);
4744                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4745         }
4746 #else
4747         if (index->type == STACK_I8) {
4748                 index2_reg = alloc_preg (cfg);
4749                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4750         } else {
4751                 index2_reg = index_reg;
4752         }
4753 #endif
4754
4755         if (bcheck)
4756                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4757
4758 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4759         if (size == 1 || size == 2 || size == 4 || size == 8) {
4760                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4761
4762                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
4763                 ins->klass = mono_class_get_element_class (klass);
4764                 ins->type = STACK_MP;
4765
4766                 return ins;
4767         }
4768 #endif          
4769
4770         add_reg = alloc_ireg_mp (cfg);
4771
4772         if (size == -1) {
4773                 MonoInst *rgctx_ins;
4774
4775                 /* gsharedvt */
4776                 g_assert (cfg->gshared);
4777                 context_used = mini_class_check_context_used (cfg, klass);
4778                 g_assert (context_used);
4779                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4780                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4781         } else {
4782                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4783         }
4784         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4785         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4786         ins->klass = mono_class_get_element_class (klass);
4787         ins->type = STACK_MP;
4788         MONO_ADD_INS (cfg->cbb, ins);
4789
4790         return ins;
4791 }
4792
4793 static MonoInst*
4794 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4795 {
4796         int bounds_reg = alloc_preg (cfg);
4797         int add_reg = alloc_ireg_mp (cfg);
4798         int mult_reg = alloc_preg (cfg);
4799         int mult2_reg = alloc_preg (cfg);
4800         int low1_reg = alloc_preg (cfg);
4801         int low2_reg = alloc_preg (cfg);
4802         int high1_reg = alloc_preg (cfg);
4803         int high2_reg = alloc_preg (cfg);
4804         int realidx1_reg = alloc_preg (cfg);
4805         int realidx2_reg = alloc_preg (cfg);
4806         int sum_reg = alloc_preg (cfg);
4807         int index1, index2, tmpreg;
4808         MonoInst *ins;
4809         guint32 size;
4810
4811         mono_class_init (klass);
4812         size = mono_class_array_element_size (klass);
4813
4814         index1 = index_ins1->dreg;
4815         index2 = index_ins2->dreg;
4816
4817 #if SIZEOF_REGISTER == 8
4818         /* The array reg is 64 bits but the index reg is only 32 */
4819         if (COMPILE_LLVM (cfg)) {
4820                 /* Not needed */
4821         } else {
4822                 tmpreg = alloc_preg (cfg);
4823                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4824                 index1 = tmpreg;
4825                 tmpreg = alloc_preg (cfg);
4826                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4827                 index2 = tmpreg;
4828         }
4829 #else
4830         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4831         tmpreg = -1;
4832 #endif
4833
4834         /* range checking */
4835         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4836                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4837
4838         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4839                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4840         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4841         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4842                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4843         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4844         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4845
4846         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4847                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4848         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4849         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4850                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4851         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4852         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4853
4854         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4855         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4856         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4857         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4858         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4859
4860         ins->type = STACK_MP;
4861         ins->klass = klass;
4862         MONO_ADD_INS (cfg->cbb, ins);
4863
4864         return ins;
4865 }
4866
4867 static MonoInst*
4868 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4869 {
4870         int rank;
4871         MonoInst *addr;
4872         MonoMethod *addr_method;
4873         int element_size;
4874         MonoClass *eclass = cmethod->klass->element_class;
4875
4876         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4877
4878         if (rank == 1)
4879                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
4880
4881         /* emit_ldelema_2 depends on OP_LMUL */
4882         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
4883                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
4884         }
4885
4886         if (mini_is_gsharedvt_variable_klass (eclass))
4887                 element_size = 0;
4888         else
4889                 element_size = mono_class_array_element_size (eclass);
4890         addr_method = mono_marshal_get_array_address (rank, element_size);
4891         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4892
4893         return addr;
4894 }
4895
4896 static MonoBreakPolicy
4897 always_insert_breakpoint (MonoMethod *method)
4898 {
4899         return MONO_BREAK_POLICY_ALWAYS;
4900 }
4901
4902 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4903
4904 /**
4905  * mono_set_break_policy:
4906  * policy_callback: the new callback function
4907  *
4908  * Allow embedders to decide wherther to actually obey breakpoint instructions
4909  * (both break IL instructions and Debugger.Break () method calls), for example
4910  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4911  * untrusted or semi-trusted code.
4912  *
4913  * @policy_callback will be called every time a break point instruction needs to
4914  * be inserted with the method argument being the method that calls Debugger.Break()
4915  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4916  * if it wants the breakpoint to not be effective in the given method.
4917  * #MONO_BREAK_POLICY_ALWAYS is the default.
4918  */
4919 void
4920 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4921 {
4922         if (policy_callback)
4923                 break_policy_func = policy_callback;
4924         else
4925                 break_policy_func = always_insert_breakpoint;
4926 }
4927
4928 static gboolean
4929 should_insert_brekpoint (MonoMethod *method) {
4930         switch (break_policy_func (method)) {
4931         case MONO_BREAK_POLICY_ALWAYS:
4932                 return TRUE;
4933         case MONO_BREAK_POLICY_NEVER:
4934                 return FALSE;
4935         case MONO_BREAK_POLICY_ON_DBG:
4936                 g_warning ("mdb no longer supported");
4937                 return FALSE;
4938         default:
4939                 g_warning ("Incorrect value returned from break policy callback");
4940                 return FALSE;
4941         }
4942 }
4943
4944 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4945 static MonoInst*
4946 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4947 {
4948         MonoInst *addr, *store, *load;
4949         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4950
4951         /* the bounds check is already done by the callers */
4952         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4953         if (is_set) {
4954                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4955                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4956                 if (mini_type_is_reference (&eklass->byval_arg))
4957                         emit_write_barrier (cfg, addr, load);
4958         } else {
4959                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4960                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4961         }
4962         return store;
4963 }
4964
4965
4966 static gboolean
4967 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4968 {
4969         return mini_type_is_reference (&klass->byval_arg);
4970 }
4971
4972 static MonoInst*
4973 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
4974 {
4975         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
4976                 !(MONO_INS_IS_PCONST_NULL (sp [2]))) {
4977                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
4978                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
4979                 MonoInst *iargs [3];
4980
4981                 if (!helper->slot)
4982                         mono_class_setup_vtable (obj_array);
4983                 g_assert (helper->slot);
4984
4985                 if (sp [0]->type != STACK_OBJ)
4986                         return NULL;
4987                 if (sp [2]->type != STACK_OBJ)
4988                         return NULL;
4989
4990                 iargs [2] = sp [2];
4991                 iargs [1] = sp [1];
4992                 iargs [0] = sp [0];
4993
4994                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
4995         } else {
4996                 MonoInst *ins;
4997
4998                 if (mini_is_gsharedvt_variable_klass (klass)) {
4999                         MonoInst *addr;
5000
5001                         // FIXME-VT: OP_ICONST optimization
5002                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5003                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5004                         ins->opcode = OP_STOREV_MEMBASE;
5005                 } else if (sp [1]->opcode == OP_ICONST) {
5006                         int array_reg = sp [0]->dreg;
5007                         int index_reg = sp [1]->dreg;
5008                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5009
5010                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5011                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5012
5013                         if (safety_checks)
5014                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5015                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5016                 } else {
5017                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5018                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5019                         if (generic_class_is_reference_type (cfg, klass))
5020                                 emit_write_barrier (cfg, addr, sp [2]);
5021                 }
5022                 return ins;
5023         }
5024 }
5025
5026 static MonoInst*
5027 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5028 {
5029         MonoClass *eklass;
5030         
5031         if (is_set)
5032                 eklass = mono_class_from_mono_type (fsig->params [2]);
5033         else
5034                 eklass = mono_class_from_mono_type (fsig->ret);
5035
5036         if (is_set) {
5037                 return emit_array_store (cfg, eklass, args, FALSE);
5038         } else {
5039                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5040                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5041                 return ins;
5042         }
5043 }
5044
5045 static gboolean
5046 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5047 {
5048         uint32_t align;
5049         int param_size, return_size;
5050
5051         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5052         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5053
5054         if (cfg->verbose_level > 3)
5055                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5056
5057         //Don't allow mixing reference types with value types
5058         if (param_klass->valuetype != return_klass->valuetype) {
5059                 if (cfg->verbose_level > 3)
5060                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5061                 return FALSE;
5062         }
5063
5064         if (!param_klass->valuetype) {
5065                 if (cfg->verbose_level > 3)
5066                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5067                 return TRUE;
5068         }
5069
5070         //That are blitable
5071         if (param_klass->has_references || return_klass->has_references)
5072                 return FALSE;
5073
5074         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5075         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5076                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5077                         if (cfg->verbose_level > 3)
5078                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5079                 return FALSE;
5080         }
5081
5082         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5083                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5084                 if (cfg->verbose_level > 3)
5085                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5086                 return FALSE;
5087         }
5088
5089         param_size = mono_class_value_size (param_klass, &align);
5090         return_size = mono_class_value_size (return_klass, &align);
5091
5092         //We can do it if sizes match
5093         if (param_size == return_size) {
5094                 if (cfg->verbose_level > 3)
5095                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5096                 return TRUE;
5097         }
5098
5099         //No simple way to handle struct if sizes don't match
5100         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5101                 if (cfg->verbose_level > 3)
5102                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5103                 return FALSE;
5104         }
5105
5106         /*
5107          * Same reg size category.
5108          * A quick note on why we don't require widening here.
5109          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5110          *
5111          * Since the source value comes from a function argument, the JIT will already have
5112          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5113          */
5114         if (param_size <= 4 && return_size <= 4) {
5115                 if (cfg->verbose_level > 3)
5116                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5117                 return TRUE;
5118         }
5119
5120         return FALSE;
5121 }
5122
5123 static MonoInst*
5124 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5125 {
5126         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5127         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5128
5129         if (mini_is_gsharedvt_variable_type (fsig->ret))
5130                 return NULL;
5131
5132         //Valuetypes that are semantically equivalent or numbers than can be widened to
5133         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5134                 return args [0];
5135
5136         //Arrays of valuetypes that are semantically equivalent
5137         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5138                 return args [0];
5139
5140         return NULL;
5141 }
5142
5143 static MonoInst*
5144 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5145 {
5146 #ifdef MONO_ARCH_SIMD_INTRINSICS
5147         MonoInst *ins = NULL;
5148
5149         if (cfg->opt & MONO_OPT_SIMD) {
5150                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5151                 if (ins)
5152                         return ins;
5153         }
5154 #endif
5155
5156         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5157 }
5158
5159 static MonoInst*
5160 emit_memory_barrier (MonoCompile *cfg, int kind)
5161 {
5162         MonoInst *ins = NULL;
5163         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5164         MONO_ADD_INS (cfg->cbb, ins);
5165         ins->backend.memory_barrier_kind = kind;
5166
5167         return ins;
5168 }
5169
5170 static MonoInst*
5171 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5172 {
5173         MonoInst *ins = NULL;
5174         int opcode = 0;
5175
5176         /* The LLVM backend supports these intrinsics */
5177         if (cmethod->klass == mono_defaults.math_class) {
5178                 if (strcmp (cmethod->name, "Sin") == 0) {
5179                         opcode = OP_SIN;
5180                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5181                         opcode = OP_COS;
5182                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5183                         opcode = OP_SQRT;
5184                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5185                         opcode = OP_ABS;
5186                 }
5187
5188                 if (opcode && fsig->param_count == 1) {
5189                         MONO_INST_NEW (cfg, ins, opcode);
5190                         ins->type = STACK_R8;
5191                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5192                         ins->sreg1 = args [0]->dreg;
5193                         MONO_ADD_INS (cfg->cbb, ins);
5194                 }
5195
5196                 opcode = 0;
5197                 if (cfg->opt & MONO_OPT_CMOV) {
5198                         if (strcmp (cmethod->name, "Min") == 0) {
5199                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5200                                         opcode = OP_IMIN;
5201                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5202                                         opcode = OP_IMIN_UN;
5203                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5204                                         opcode = OP_LMIN;
5205                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5206                                         opcode = OP_LMIN_UN;
5207                         } else if (strcmp (cmethod->name, "Max") == 0) {
5208                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5209                                         opcode = OP_IMAX;
5210                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5211                                         opcode = OP_IMAX_UN;
5212                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5213                                         opcode = OP_LMAX;
5214                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5215                                         opcode = OP_LMAX_UN;
5216                         }
5217                 }
5218
5219                 if (opcode && fsig->param_count == 2) {
5220                         MONO_INST_NEW (cfg, ins, opcode);
5221                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5222                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5223                         ins->sreg1 = args [0]->dreg;
5224                         ins->sreg2 = args [1]->dreg;
5225                         MONO_ADD_INS (cfg->cbb, ins);
5226                 }
5227         }
5228
5229         return ins;
5230 }
5231
5232 static MonoInst*
5233 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5234 {
5235         if (cmethod->klass == mono_defaults.array_class) {
5236                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5237                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5238                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5239                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5240                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5241                         return emit_array_unsafe_mov (cfg, fsig, args);
5242         }
5243
5244         return NULL;
5245 }
5246
5247 static MonoInst*
5248 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5249 {
5250         MonoInst *ins = NULL;
5251
5252          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5253
5254         if (cmethod->klass == mono_defaults.string_class) {
5255                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5256                         int dreg = alloc_ireg (cfg);
5257                         int index_reg = alloc_preg (cfg);
5258                         int add_reg = alloc_preg (cfg);
5259
5260 #if SIZEOF_REGISTER == 8
5261                         if (COMPILE_LLVM (cfg)) {
5262                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5263                         } else {
5264                                 /* The array reg is 64 bits but the index reg is only 32 */
5265                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5266                         }
5267 #else
5268                         index_reg = args [1]->dreg;
5269 #endif  
5270                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5271
5272 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5273                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5274                         add_reg = ins->dreg;
5275                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5276                                                                    add_reg, 0);
5277 #else
5278                         int mult_reg = alloc_preg (cfg);
5279                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5280                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5281                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5282                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5283 #endif
5284                         type_from_op (cfg, ins, NULL, NULL);
5285                         return ins;
5286                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5287                         int dreg = alloc_ireg (cfg);
5288                         /* Decompose later to allow more optimizations */
5289                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5290                         ins->type = STACK_I4;
5291                         ins->flags |= MONO_INST_FAULT;
5292                         cfg->cbb->has_array_access = TRUE;
5293                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5294
5295                         return ins;
5296                 } else 
5297                         return NULL;
5298         } else if (cmethod->klass == mono_defaults.object_class) {
5299                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5300                         int dreg = alloc_ireg_ref (cfg);
5301                         int vt_reg = alloc_preg (cfg);
5302                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5303                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5304                         type_from_op (cfg, ins, NULL, NULL);
5305
5306                         return ins;
5307                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5308                         int dreg = alloc_ireg (cfg);
5309                         int t1 = alloc_ireg (cfg);
5310         
5311                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5312                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5313                         ins->type = STACK_I4;
5314
5315                         return ins;
5316                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5317                         MONO_INST_NEW (cfg, ins, OP_NOP);
5318                         MONO_ADD_INS (cfg->cbb, ins);
5319                         return ins;
5320                 } else
5321                         return NULL;
5322         } else if (cmethod->klass == mono_defaults.array_class) {
5323                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5324                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5325                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5326                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5327
5328 #ifndef MONO_BIG_ARRAYS
5329                 /*
5330                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5331                  * Array methods.
5332                  */
5333                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5334                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5335                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5336                         int dreg = alloc_ireg (cfg);
5337                         int bounds_reg = alloc_ireg_mp (cfg);
5338                         MonoBasicBlock *end_bb, *szarray_bb;
5339                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5340
5341                         NEW_BBLOCK (cfg, end_bb);
5342                         NEW_BBLOCK (cfg, szarray_bb);
5343
5344                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5345                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5346                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5347                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5348                         /* Non-szarray case */
5349                         if (get_length)
5350                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5351                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5352                         else
5353                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5354                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5355                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5356                         MONO_START_BB (cfg, szarray_bb);
5357                         /* Szarray case */
5358                         if (get_length)
5359                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5360                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5361                         else
5362                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5363                         MONO_START_BB (cfg, end_bb);
5364
5365                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5366                         ins->type = STACK_I4;
5367                         
5368                         return ins;
5369                 }
5370 #endif
5371
5372                 if (cmethod->name [0] != 'g')
5373                         return NULL;
5374
5375                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5376                         int dreg = alloc_ireg (cfg);
5377                         int vtable_reg = alloc_preg (cfg);
5378                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5379                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5380                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5381                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5382                         type_from_op (cfg, ins, NULL, NULL);
5383
5384                         return ins;
5385                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5386                         int dreg = alloc_ireg (cfg);
5387
5388                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5389                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5390                         type_from_op (cfg, ins, NULL, NULL);
5391
5392                         return ins;
5393                 } else
5394                         return NULL;
5395         } else if (cmethod->klass == runtime_helpers_class) {
5396                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5397                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5398                         return ins;
5399                 } else
5400                         return NULL;
5401         } else if (cmethod->klass == mono_defaults.monitor_class) {
5402                 gboolean is_enter = FALSE;
5403                 gboolean is_v4 = FALSE;
5404
5405                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 2 && fsig->params [1]->byref) {
5406                         is_enter = TRUE;
5407                         is_v4 = TRUE;
5408                 }
5409                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 1)
5410                         is_enter = TRUE;
5411
5412                 if (is_enter) {
5413                         /*
5414                          * To make async stack traces work, icalls which can block should have a wrapper.
5415                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
5416                          */
5417                         MonoBasicBlock *end_bb;
5418
5419                         NEW_BBLOCK (cfg, end_bb);
5420
5421                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
5422                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
5423                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
5424                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_internal : (gpointer)mono_monitor_enter_internal, args);
5425                         MONO_START_BB (cfg, end_bb);
5426                         return ins;
5427                 }
5428         } else if (cmethod->klass == mono_defaults.thread_class) {
5429                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5430                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5431                         MONO_ADD_INS (cfg->cbb, ins);
5432                         return ins;
5433                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5434                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5435                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5436                         guint32 opcode = 0;
5437                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5438
5439                         if (fsig->params [0]->type == MONO_TYPE_I1)
5440                                 opcode = OP_LOADI1_MEMBASE;
5441                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5442                                 opcode = OP_LOADU1_MEMBASE;
5443                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5444                                 opcode = OP_LOADI2_MEMBASE;
5445                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5446                                 opcode = OP_LOADU2_MEMBASE;
5447                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5448                                 opcode = OP_LOADI4_MEMBASE;
5449                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5450                                 opcode = OP_LOADU4_MEMBASE;
5451                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5452                                 opcode = OP_LOADI8_MEMBASE;
5453                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5454                                 opcode = OP_LOADR4_MEMBASE;
5455                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5456                                 opcode = OP_LOADR8_MEMBASE;
5457                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5458                                 opcode = OP_LOAD_MEMBASE;
5459
5460                         if (opcode) {
5461                                 MONO_INST_NEW (cfg, ins, opcode);
5462                                 ins->inst_basereg = args [0]->dreg;
5463                                 ins->inst_offset = 0;
5464                                 MONO_ADD_INS (cfg->cbb, ins);
5465
5466                                 switch (fsig->params [0]->type) {
5467                                 case MONO_TYPE_I1:
5468                                 case MONO_TYPE_U1:
5469                                 case MONO_TYPE_I2:
5470                                 case MONO_TYPE_U2:
5471                                 case MONO_TYPE_I4:
5472                                 case MONO_TYPE_U4:
5473                                         ins->dreg = mono_alloc_ireg (cfg);
5474                                         ins->type = STACK_I4;
5475                                         break;
5476                                 case MONO_TYPE_I8:
5477                                 case MONO_TYPE_U8:
5478                                         ins->dreg = mono_alloc_lreg (cfg);
5479                                         ins->type = STACK_I8;
5480                                         break;
5481                                 case MONO_TYPE_I:
5482                                 case MONO_TYPE_U:
5483                                         ins->dreg = mono_alloc_ireg (cfg);
5484 #if SIZEOF_REGISTER == 8
5485                                         ins->type = STACK_I8;
5486 #else
5487                                         ins->type = STACK_I4;
5488 #endif
5489                                         break;
5490                                 case MONO_TYPE_R4:
5491                                 case MONO_TYPE_R8:
5492                                         ins->dreg = mono_alloc_freg (cfg);
5493                                         ins->type = STACK_R8;
5494                                         break;
5495                                 default:
5496                                         g_assert (mini_type_is_reference (fsig->params [0]));
5497                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5498                                         ins->type = STACK_OBJ;
5499                                         break;
5500                                 }
5501
5502                                 if (opcode == OP_LOADI8_MEMBASE)
5503                                         ins = mono_decompose_opcode (cfg, ins);
5504
5505                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5506
5507                                 return ins;
5508                         }
5509                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5510                         guint32 opcode = 0;
5511                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5512
5513                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5514                                 opcode = OP_STOREI1_MEMBASE_REG;
5515                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5516                                 opcode = OP_STOREI2_MEMBASE_REG;
5517                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5518                                 opcode = OP_STOREI4_MEMBASE_REG;
5519                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5520                                 opcode = OP_STOREI8_MEMBASE_REG;
5521                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5522                                 opcode = OP_STORER4_MEMBASE_REG;
5523                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5524                                 opcode = OP_STORER8_MEMBASE_REG;
5525                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5526                                 opcode = OP_STORE_MEMBASE_REG;
5527
5528                         if (opcode) {
5529                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5530
5531                                 MONO_INST_NEW (cfg, ins, opcode);
5532                                 ins->sreg1 = args [1]->dreg;
5533                                 ins->inst_destbasereg = args [0]->dreg;
5534                                 ins->inst_offset = 0;
5535                                 MONO_ADD_INS (cfg->cbb, ins);
5536
5537                                 if (opcode == OP_STOREI8_MEMBASE_REG)
5538                                         ins = mono_decompose_opcode (cfg, ins);
5539
5540                                 return ins;
5541                         }
5542                 }
5543         } else if (cmethod->klass->image == mono_defaults.corlib &&
5544                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5545                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5546                 ins = NULL;
5547
5548 #if SIZEOF_REGISTER == 8
5549                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5550                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
5551                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
5552                                 ins->dreg = mono_alloc_preg (cfg);
5553                                 ins->sreg1 = args [0]->dreg;
5554                                 ins->type = STACK_I8;
5555                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
5556                                 MONO_ADD_INS (cfg->cbb, ins);
5557                         } else {
5558                                 MonoInst *load_ins;
5559
5560                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5561
5562                                 /* 64 bit reads are already atomic */
5563                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
5564                                 load_ins->dreg = mono_alloc_preg (cfg);
5565                                 load_ins->inst_basereg = args [0]->dreg;
5566                                 load_ins->inst_offset = 0;
5567                                 load_ins->type = STACK_I8;
5568                                 MONO_ADD_INS (cfg->cbb, load_ins);
5569
5570                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5571
5572                                 ins = load_ins;
5573                         }
5574                 }
5575 #endif
5576
5577                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
5578                         MonoInst *ins_iconst;
5579                         guint32 opcode = 0;
5580
5581                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5582                                 opcode = OP_ATOMIC_ADD_I4;
5583                                 cfg->has_atomic_add_i4 = TRUE;
5584                         }
5585 #if SIZEOF_REGISTER == 8
5586                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5587                                 opcode = OP_ATOMIC_ADD_I8;
5588 #endif
5589                         if (opcode) {
5590                                 if (!mono_arch_opcode_supported (opcode))
5591                                         return NULL;
5592                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5593                                 ins_iconst->inst_c0 = 1;
5594                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5595                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5596
5597                                 MONO_INST_NEW (cfg, ins, opcode);
5598                                 ins->dreg = mono_alloc_ireg (cfg);
5599                                 ins->inst_basereg = args [0]->dreg;
5600                                 ins->inst_offset = 0;
5601                                 ins->sreg2 = ins_iconst->dreg;
5602                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5603                                 MONO_ADD_INS (cfg->cbb, ins);
5604                         }
5605                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
5606                         MonoInst *ins_iconst;
5607                         guint32 opcode = 0;
5608
5609                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5610                                 opcode = OP_ATOMIC_ADD_I4;
5611                                 cfg->has_atomic_add_i4 = TRUE;
5612                         }
5613 #if SIZEOF_REGISTER == 8
5614                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5615                                 opcode = OP_ATOMIC_ADD_I8;
5616 #endif
5617                         if (opcode) {
5618                                 if (!mono_arch_opcode_supported (opcode))
5619                                         return NULL;
5620                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5621                                 ins_iconst->inst_c0 = -1;
5622                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5623                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5624
5625                                 MONO_INST_NEW (cfg, ins, opcode);
5626                                 ins->dreg = mono_alloc_ireg (cfg);
5627                                 ins->inst_basereg = args [0]->dreg;
5628                                 ins->inst_offset = 0;
5629                                 ins->sreg2 = ins_iconst->dreg;
5630                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5631                                 MONO_ADD_INS (cfg->cbb, ins);
5632                         }
5633                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
5634                         guint32 opcode = 0;
5635
5636                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5637                                 opcode = OP_ATOMIC_ADD_I4;
5638                                 cfg->has_atomic_add_i4 = TRUE;
5639                         }
5640 #if SIZEOF_REGISTER == 8
5641                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5642                                 opcode = OP_ATOMIC_ADD_I8;
5643 #endif
5644                         if (opcode) {
5645                                 if (!mono_arch_opcode_supported (opcode))
5646                                         return NULL;
5647                                 MONO_INST_NEW (cfg, ins, opcode);
5648                                 ins->dreg = mono_alloc_ireg (cfg);
5649                                 ins->inst_basereg = args [0]->dreg;
5650                                 ins->inst_offset = 0;
5651                                 ins->sreg2 = args [1]->dreg;
5652                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5653                                 MONO_ADD_INS (cfg->cbb, ins);
5654                         }
5655                 }
5656                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
5657                         MonoInst *f2i = NULL, *i2f;
5658                         guint32 opcode, f2i_opcode, i2f_opcode;
5659                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5660                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
5661
5662                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
5663                             fsig->params [0]->type == MONO_TYPE_R4) {
5664                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5665                                 f2i_opcode = OP_MOVE_F_TO_I4;
5666                                 i2f_opcode = OP_MOVE_I4_TO_F;
5667                                 cfg->has_atomic_exchange_i4 = TRUE;
5668                         }
5669 #if SIZEOF_REGISTER == 8
5670                         else if (is_ref ||
5671                                  fsig->params [0]->type == MONO_TYPE_I8 ||
5672                                  fsig->params [0]->type == MONO_TYPE_R8 ||
5673                                  fsig->params [0]->type == MONO_TYPE_I) {
5674                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5675                                 f2i_opcode = OP_MOVE_F_TO_I8;
5676                                 i2f_opcode = OP_MOVE_I8_TO_F;
5677                         }
5678 #else
5679                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
5680                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5681                                 cfg->has_atomic_exchange_i4 = TRUE;
5682                         }
5683 #endif
5684                         else
5685                                 return NULL;
5686
5687                         if (!mono_arch_opcode_supported (opcode))
5688                                 return NULL;
5689
5690                         if (is_float) {
5691                                 /* TODO: Decompose these opcodes instead of bailing here. */
5692                                 if (COMPILE_SOFT_FLOAT (cfg))
5693                                         return NULL;
5694
5695                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
5696                                 f2i->dreg = mono_alloc_ireg (cfg);
5697                                 f2i->sreg1 = args [1]->dreg;
5698                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5699                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5700                                 MONO_ADD_INS (cfg->cbb, f2i);
5701                         }
5702
5703                         MONO_INST_NEW (cfg, ins, opcode);
5704                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5705                         ins->inst_basereg = args [0]->dreg;
5706                         ins->inst_offset = 0;
5707                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
5708                         MONO_ADD_INS (cfg->cbb, ins);
5709
5710                         switch (fsig->params [0]->type) {
5711                         case MONO_TYPE_I4:
5712                                 ins->type = STACK_I4;
5713                                 break;
5714                         case MONO_TYPE_I8:
5715                                 ins->type = STACK_I8;
5716                                 break;
5717                         case MONO_TYPE_I:
5718 #if SIZEOF_REGISTER == 8
5719                                 ins->type = STACK_I8;
5720 #else
5721                                 ins->type = STACK_I4;
5722 #endif
5723                                 break;
5724                         case MONO_TYPE_R4:
5725                         case MONO_TYPE_R8:
5726                                 ins->type = STACK_R8;
5727                                 break;
5728                         default:
5729                                 g_assert (mini_type_is_reference (fsig->params [0]));
5730                                 ins->type = STACK_OBJ;
5731                                 break;
5732                         }
5733
5734                         if (is_float) {
5735                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5736                                 i2f->dreg = mono_alloc_freg (cfg);
5737                                 i2f->sreg1 = ins->dreg;
5738                                 i2f->type = STACK_R8;
5739                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5740                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5741                                 MONO_ADD_INS (cfg->cbb, i2f);
5742
5743                                 ins = i2f;
5744                         }
5745
5746                         if (cfg->gen_write_barriers && is_ref)
5747                                 emit_write_barrier (cfg, args [0], args [1]);
5748                 }
5749                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
5750                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
5751                         guint32 opcode, f2i_opcode, i2f_opcode;
5752                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
5753                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
5754
5755                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
5756                             fsig->params [1]->type == MONO_TYPE_R4) {
5757                                 opcode = OP_ATOMIC_CAS_I4;
5758                                 f2i_opcode = OP_MOVE_F_TO_I4;
5759                                 i2f_opcode = OP_MOVE_I4_TO_F;
5760                                 cfg->has_atomic_cas_i4 = TRUE;
5761                         }
5762 #if SIZEOF_REGISTER == 8
5763                         else if (is_ref ||
5764                                  fsig->params [1]->type == MONO_TYPE_I8 ||
5765                                  fsig->params [1]->type == MONO_TYPE_R8 ||
5766                                  fsig->params [1]->type == MONO_TYPE_I) {
5767                                 opcode = OP_ATOMIC_CAS_I8;
5768                                 f2i_opcode = OP_MOVE_F_TO_I8;
5769                                 i2f_opcode = OP_MOVE_I8_TO_F;
5770                         }
5771 #else
5772                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
5773                                 opcode = OP_ATOMIC_CAS_I4;
5774                                 cfg->has_atomic_cas_i4 = TRUE;
5775                         }
5776 #endif
5777                         else
5778                                 return NULL;
5779
5780                         if (!mono_arch_opcode_supported (opcode))
5781                                 return NULL;
5782
5783                         if (is_float) {
5784                                 /* TODO: Decompose these opcodes instead of bailing here. */
5785                                 if (COMPILE_SOFT_FLOAT (cfg))
5786                                         return NULL;
5787
5788                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
5789                                 f2i_new->dreg = mono_alloc_ireg (cfg);
5790                                 f2i_new->sreg1 = args [1]->dreg;
5791                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5792                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5793                                 MONO_ADD_INS (cfg->cbb, f2i_new);
5794
5795                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
5796                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
5797                                 f2i_cmp->sreg1 = args [2]->dreg;
5798                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5799                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5800                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
5801                         }
5802
5803                         MONO_INST_NEW (cfg, ins, opcode);
5804                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5805                         ins->sreg1 = args [0]->dreg;
5806                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
5807                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
5808                         MONO_ADD_INS (cfg->cbb, ins);
5809
5810                         switch (fsig->params [1]->type) {
5811                         case MONO_TYPE_I4:
5812                                 ins->type = STACK_I4;
5813                                 break;
5814                         case MONO_TYPE_I8:
5815                                 ins->type = STACK_I8;
5816                                 break;
5817                         case MONO_TYPE_I:
5818 #if SIZEOF_REGISTER == 8
5819                                 ins->type = STACK_I8;
5820 #else
5821                                 ins->type = STACK_I4;
5822 #endif
5823                                 break;
5824                         case MONO_TYPE_R4:
5825                                 ins->type = cfg->r4_stack_type;
5826                                 break;
5827                         case MONO_TYPE_R8:
5828                                 ins->type = STACK_R8;
5829                                 break;
5830                         default:
5831                                 g_assert (mini_type_is_reference (fsig->params [1]));
5832                                 ins->type = STACK_OBJ;
5833                                 break;
5834                         }
5835
5836                         if (is_float) {
5837                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5838                                 i2f->dreg = mono_alloc_freg (cfg);
5839                                 i2f->sreg1 = ins->dreg;
5840                                 i2f->type = STACK_R8;
5841                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5842                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5843                                 MONO_ADD_INS (cfg->cbb, i2f);
5844
5845                                 ins = i2f;
5846                         }
5847
5848                         if (cfg->gen_write_barriers && is_ref)
5849                                 emit_write_barrier (cfg, args [0], args [1]);
5850                 }
5851                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
5852                          fsig->params [1]->type == MONO_TYPE_I4) {
5853                         MonoInst *cmp, *ceq;
5854
5855                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5856                                 return NULL;
5857
5858                         /* int32 r = CAS (location, value, comparand); */
5859                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5860                         ins->dreg = alloc_ireg (cfg);
5861                         ins->sreg1 = args [0]->dreg;
5862                         ins->sreg2 = args [1]->dreg;
5863                         ins->sreg3 = args [2]->dreg;
5864                         ins->type = STACK_I4;
5865                         MONO_ADD_INS (cfg->cbb, ins);
5866
5867                         /* bool result = r == comparand; */
5868                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
5869                         cmp->sreg1 = ins->dreg;
5870                         cmp->sreg2 = args [2]->dreg;
5871                         cmp->type = STACK_I4;
5872                         MONO_ADD_INS (cfg->cbb, cmp);
5873
5874                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
5875                         ceq->dreg = alloc_ireg (cfg);
5876                         ceq->type = STACK_I4;
5877                         MONO_ADD_INS (cfg->cbb, ceq);
5878
5879                         /* *success = result; */
5880                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
5881
5882                         cfg->has_atomic_cas_i4 = TRUE;
5883                 }
5884                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
5885                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5886
5887                 if (ins)
5888                         return ins;
5889         } else if (cmethod->klass->image == mono_defaults.corlib &&
5890                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5891                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
5892                 ins = NULL;
5893
5894                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
5895                         guint32 opcode = 0;
5896                         MonoType *t = fsig->params [0];
5897                         gboolean is_ref;
5898                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
5899
5900                         g_assert (t->byref);
5901                         /* t is a byref type, so the reference check is more complicated */
5902                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5903                         if (t->type == MONO_TYPE_I1)
5904                                 opcode = OP_ATOMIC_LOAD_I1;
5905                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5906                                 opcode = OP_ATOMIC_LOAD_U1;
5907                         else if (t->type == MONO_TYPE_I2)
5908                                 opcode = OP_ATOMIC_LOAD_I2;
5909                         else if (t->type == MONO_TYPE_U2)
5910                                 opcode = OP_ATOMIC_LOAD_U2;
5911                         else if (t->type == MONO_TYPE_I4)
5912                                 opcode = OP_ATOMIC_LOAD_I4;
5913                         else if (t->type == MONO_TYPE_U4)
5914                                 opcode = OP_ATOMIC_LOAD_U4;
5915                         else if (t->type == MONO_TYPE_R4)
5916                                 opcode = OP_ATOMIC_LOAD_R4;
5917                         else if (t->type == MONO_TYPE_R8)
5918                                 opcode = OP_ATOMIC_LOAD_R8;
5919 #if SIZEOF_REGISTER == 8
5920                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
5921                                 opcode = OP_ATOMIC_LOAD_I8;
5922                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
5923                                 opcode = OP_ATOMIC_LOAD_U8;
5924 #else
5925                         else if (t->type == MONO_TYPE_I)
5926                                 opcode = OP_ATOMIC_LOAD_I4;
5927                         else if (is_ref || t->type == MONO_TYPE_U)
5928                                 opcode = OP_ATOMIC_LOAD_U4;
5929 #endif
5930
5931                         if (opcode) {
5932                                 if (!mono_arch_opcode_supported (opcode))
5933                                         return NULL;
5934
5935                                 MONO_INST_NEW (cfg, ins, opcode);
5936                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
5937                                 ins->sreg1 = args [0]->dreg;
5938                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
5939                                 MONO_ADD_INS (cfg->cbb, ins);
5940
5941                                 switch (t->type) {
5942                                 case MONO_TYPE_BOOLEAN:
5943                                 case MONO_TYPE_I1:
5944                                 case MONO_TYPE_U1:
5945                                 case MONO_TYPE_I2:
5946                                 case MONO_TYPE_U2:
5947                                 case MONO_TYPE_I4:
5948                                 case MONO_TYPE_U4:
5949                                         ins->type = STACK_I4;
5950                                         break;
5951                                 case MONO_TYPE_I8:
5952                                 case MONO_TYPE_U8:
5953                                         ins->type = STACK_I8;
5954                                         break;
5955                                 case MONO_TYPE_I:
5956                                 case MONO_TYPE_U:
5957 #if SIZEOF_REGISTER == 8
5958                                         ins->type = STACK_I8;
5959 #else
5960                                         ins->type = STACK_I4;
5961 #endif
5962                                         break;
5963                                 case MONO_TYPE_R4:
5964                                         ins->type = cfg->r4_stack_type;
5965                                         break;
5966                                 case MONO_TYPE_R8:
5967                                         ins->type = STACK_R8;
5968                                         break;
5969                                 default:
5970                                         g_assert (is_ref);
5971                                         ins->type = STACK_OBJ;
5972                                         break;
5973                                 }
5974                         }
5975                 }
5976
5977                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
5978                         guint32 opcode = 0;
5979                         MonoType *t = fsig->params [0];
5980                         gboolean is_ref;
5981
5982                         g_assert (t->byref);
5983                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5984                         if (t->type == MONO_TYPE_I1)
5985                                 opcode = OP_ATOMIC_STORE_I1;
5986                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5987                                 opcode = OP_ATOMIC_STORE_U1;
5988                         else if (t->type == MONO_TYPE_I2)
5989                                 opcode = OP_ATOMIC_STORE_I2;
5990                         else if (t->type == MONO_TYPE_U2)
5991                                 opcode = OP_ATOMIC_STORE_U2;
5992                         else if (t->type == MONO_TYPE_I4)
5993                                 opcode = OP_ATOMIC_STORE_I4;
5994                         else if (t->type == MONO_TYPE_U4)
5995                                 opcode = OP_ATOMIC_STORE_U4;
5996                         else if (t->type == MONO_TYPE_R4)
5997                                 opcode = OP_ATOMIC_STORE_R4;
5998                         else if (t->type == MONO_TYPE_R8)
5999                                 opcode = OP_ATOMIC_STORE_R8;
6000 #if SIZEOF_REGISTER == 8
6001                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6002                                 opcode = OP_ATOMIC_STORE_I8;
6003                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6004                                 opcode = OP_ATOMIC_STORE_U8;
6005 #else
6006                         else if (t->type == MONO_TYPE_I)
6007                                 opcode = OP_ATOMIC_STORE_I4;
6008                         else if (is_ref || t->type == MONO_TYPE_U)
6009                                 opcode = OP_ATOMIC_STORE_U4;
6010 #endif
6011
6012                         if (opcode) {
6013                                 if (!mono_arch_opcode_supported (opcode))
6014                                         return NULL;
6015
6016                                 MONO_INST_NEW (cfg, ins, opcode);
6017                                 ins->dreg = args [0]->dreg;
6018                                 ins->sreg1 = args [1]->dreg;
6019                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6020                                 MONO_ADD_INS (cfg->cbb, ins);
6021
6022                                 if (cfg->gen_write_barriers && is_ref)
6023                                         emit_write_barrier (cfg, args [0], args [1]);
6024                         }
6025                 }
6026
6027                 if (ins)
6028                         return ins;
6029         } else if (cmethod->klass->image == mono_defaults.corlib &&
6030                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6031                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6032                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6033                         if (should_insert_brekpoint (cfg->method)) {
6034                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6035                         } else {
6036                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6037                                 MONO_ADD_INS (cfg->cbb, ins);
6038                         }
6039                         return ins;
6040                 }
6041         } else if (cmethod->klass->image == mono_defaults.corlib &&
6042                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6043                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6044                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6045 #ifdef TARGET_WIN32
6046                         EMIT_NEW_ICONST (cfg, ins, 1);
6047 #else
6048                         EMIT_NEW_ICONST (cfg, ins, 0);
6049 #endif
6050                 }
6051         } else if (cmethod->klass->image == mono_defaults.corlib &&
6052                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6053                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6054                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6055                         /* No stack walks are currently available, so implement this as an intrinsic */
6056                         MonoInst *assembly_ins;
6057
6058                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6059                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6060                         return ins;
6061                 }
6062         } else if (cmethod->klass->image == mono_defaults.corlib &&
6063                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6064                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6065                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6066                         /* No stack walks are currently available, so implement this as an intrinsic */
6067                         MonoInst *method_ins;
6068                         MonoMethod *declaring = cfg->method;
6069
6070                         /* This returns the declaring generic method */
6071                         if (declaring->is_inflated)
6072                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6073                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6074                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6075                         cfg->no_inline = TRUE;
6076                         if (cfg->method != cfg->current_method)
6077                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6078                         return ins;
6079                 }
6080         } else if (cmethod->klass == mono_defaults.math_class) {
6081                 /* 
6082                  * There is general branchless code for Min/Max, but it does not work for 
6083                  * all inputs:
6084                  * http://everything2.com/?node_id=1051618
6085                  */
6086         } else if (cmethod->klass == mono_defaults.systemtype_class && !strcmp (cmethod->name, "op_Equality")) {
6087                 EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg);
6088                 MONO_INST_NEW (cfg, ins, OP_PCEQ);
6089                 ins->dreg = alloc_preg (cfg);
6090                 ins->type = STACK_I4;
6091                 MONO_ADD_INS (cfg->cbb, ins);
6092                 return ins;
6093         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6094                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6095                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6096                                 !strcmp (cmethod->klass->name, "Selector")) ||
6097                            ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
6098                                  !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
6099                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6100                                 !strcmp (cmethod->klass->name, "Selector"))
6101                            ) {
6102                 if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
6103                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6104                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6105                     cfg->compile_aot) {
6106                         MonoInst *pi;
6107                         MonoJumpInfoToken *ji;
6108                         char *s;
6109
6110                         if (args [0]->opcode == OP_GOT_ENTRY) {
6111                                 pi = (MonoInst *)args [0]->inst_p1;
6112                                 g_assert (pi->opcode == OP_PATCH_INFO);
6113                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6114                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6115                         } else {
6116                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6117                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6118                         }
6119
6120                         NULLIFY_INS (args [0]);
6121
6122                         s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
6123                         return_val_if_nok (&cfg->error, NULL);
6124
6125                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6126                         ins->dreg = mono_alloc_ireg (cfg);
6127                         // FIXME: Leaks
6128                         ins->inst_p0 = s;
6129                         MONO_ADD_INS (cfg->cbb, ins);
6130                         return ins;
6131                 }
6132         }
6133
6134 #ifdef MONO_ARCH_SIMD_INTRINSICS
6135         if (cfg->opt & MONO_OPT_SIMD) {
6136                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6137                 if (ins)
6138                         return ins;
6139         }
6140 #endif
6141
6142         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6143         if (ins)
6144                 return ins;
6145
6146         if (COMPILE_LLVM (cfg)) {
6147                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6148                 if (ins)
6149                         return ins;
6150         }
6151
6152         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6153 }
6154
6155 /*
6156  * This entry point could be used later for arbitrary method
6157  * redirection.
6158  */
6159 inline static MonoInst*
6160 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6161                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6162 {
6163         if (method->klass == mono_defaults.string_class) {
6164                 /* managed string allocation support */
6165                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6166                         MonoInst *iargs [2];
6167                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6168                         MonoMethod *managed_alloc = NULL;
6169
6170                         g_assert (vtable); /*Should not fail since it System.String*/
6171 #ifndef MONO_CROSS_COMPILE
6172                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6173 #endif
6174                         if (!managed_alloc)
6175                                 return NULL;
6176                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6177                         iargs [1] = args [0];
6178                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6179                 }
6180         }
6181         return NULL;
6182 }
6183
6184 static void
6185 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6186 {
6187         MonoInst *store, *temp;
6188         int i;
6189
6190         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6191                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6192
6193                 /*
6194                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6195                  * would be different than the MonoInst's used to represent arguments, and
6196                  * the ldelema implementation can't deal with that.
6197                  * Solution: When ldelema is used on an inline argument, create a var for 
6198                  * it, emit ldelema on that var, and emit the saving code below in
6199                  * inline_method () if needed.
6200                  */
6201                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6202                 cfg->args [i] = temp;
6203                 /* This uses cfg->args [i] which is set by the preceeding line */
6204                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6205                 store->cil_code = sp [0]->cil_code;
6206                 sp++;
6207         }
6208 }
6209
6210 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6211 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6212
6213 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6214 static gboolean
6215 check_inline_called_method_name_limit (MonoMethod *called_method)
6216 {
6217         int strncmp_result;
6218         static const char *limit = NULL;
6219         
6220         if (limit == NULL) {
6221                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6222
6223                 if (limit_string != NULL)
6224                         limit = limit_string;
6225                 else
6226                         limit = "";
6227         }
6228
6229         if (limit [0] != '\0') {
6230                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6231
6232                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6233                 g_free (called_method_name);
6234         
6235                 //return (strncmp_result <= 0);
6236                 return (strncmp_result == 0);
6237         } else {
6238                 return TRUE;
6239         }
6240 }
6241 #endif
6242
6243 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6244 static gboolean
6245 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6246 {
6247         int strncmp_result;
6248         static const char *limit = NULL;
6249         
6250         if (limit == NULL) {
6251                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6252                 if (limit_string != NULL) {
6253                         limit = limit_string;
6254                 } else {
6255                         limit = "";
6256                 }
6257         }
6258
6259         if (limit [0] != '\0') {
6260                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6261
6262                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6263                 g_free (caller_method_name);
6264         
6265                 //return (strncmp_result <= 0);
6266                 return (strncmp_result == 0);
6267         } else {
6268                 return TRUE;
6269         }
6270 }
6271 #endif
6272
6273 static void
6274 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6275 {
6276         static double r8_0 = 0.0;
6277         static float r4_0 = 0.0;
6278         MonoInst *ins;
6279         int t;
6280
6281         rtype = mini_get_underlying_type (rtype);
6282         t = rtype->type;
6283
6284         if (rtype->byref) {
6285                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6286         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6287                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6288         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6289                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6290         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6291                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6292                 ins->type = STACK_R4;
6293                 ins->inst_p0 = (void*)&r4_0;
6294                 ins->dreg = dreg;
6295                 MONO_ADD_INS (cfg->cbb, ins);
6296         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6297                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6298                 ins->type = STACK_R8;
6299                 ins->inst_p0 = (void*)&r8_0;
6300                 ins->dreg = dreg;
6301                 MONO_ADD_INS (cfg->cbb, ins);
6302         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6303                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6304                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6305         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6306                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6307         } else {
6308                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6309         }
6310 }
6311
6312 static void
6313 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6314 {
6315         int t;
6316
6317         rtype = mini_get_underlying_type (rtype);
6318         t = rtype->type;
6319
6320         if (rtype->byref) {
6321                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6322         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6323                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6324         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6325                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6326         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6327                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6328         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6329                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6330         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6331                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6332                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6333         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6334                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6335         } else {
6336                 emit_init_rvar (cfg, dreg, rtype);
6337         }
6338 }
6339
6340 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6341 static void
6342 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6343 {
6344         MonoInst *var = cfg->locals [local];
6345         if (COMPILE_SOFT_FLOAT (cfg)) {
6346                 MonoInst *store;
6347                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
6348                 emit_init_rvar (cfg, reg, type);
6349                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6350         } else {
6351                 if (init)
6352                         emit_init_rvar (cfg, var->dreg, type);
6353                 else
6354                         emit_dummy_init_rvar (cfg, var->dreg, type);
6355         }
6356 }
6357
6358 int
6359 mini_inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, guchar *ip, guint real_offset, gboolean inline_always)
6360 {
6361         return inline_method (cfg, cmethod, fsig, sp, ip, real_offset, inline_always);
6362 }
6363
6364 /*
6365  * inline_method:
6366  *
6367  * Return the cost of inlining CMETHOD, or zero if it should not be inlined.
6368  */
6369 static int
6370 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6371                guchar *ip, guint real_offset, gboolean inline_always)
6372 {
6373         MonoError error;
6374         MonoInst *ins, *rvar = NULL;
6375         MonoMethodHeader *cheader;
6376         MonoBasicBlock *ebblock, *sbblock;
6377         int i, costs;
6378         MonoMethod *prev_inlined_method;
6379         MonoInst **prev_locals, **prev_args;
6380         MonoType **prev_arg_types;
6381         guint prev_real_offset;
6382         GHashTable *prev_cbb_hash;
6383         MonoBasicBlock **prev_cil_offset_to_bb;
6384         MonoBasicBlock *prev_cbb;
6385         const unsigned char *prev_ip;
6386         unsigned char *prev_cil_start;
6387         guint32 prev_cil_offset_to_bb_len;
6388         MonoMethod *prev_current_method;
6389         MonoGenericContext *prev_generic_context;
6390         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
6391
6392         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6393
6394 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6395         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6396                 return 0;
6397 #endif
6398 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6399         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6400                 return 0;
6401 #endif
6402
6403         if (!fsig)
6404                 fsig = mono_method_signature (cmethod);
6405
6406         if (cfg->verbose_level > 2)
6407                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6408
6409         if (!cmethod->inline_info) {
6410                 cfg->stat_inlineable_methods++;
6411                 cmethod->inline_info = 1;
6412         }
6413
6414         /* allocate local variables */
6415         cheader = mono_method_get_header_checked (cmethod, &error);
6416         if (!cheader) {
6417                 if (inline_always) {
6418                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
6419                         mono_error_move (&cfg->error, &error);
6420                 } else {
6421                         mono_error_cleanup (&error);
6422                 }
6423                 return 0;
6424         }
6425
6426         /*Must verify before creating locals as it can cause the JIT to assert.*/
6427         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6428                 mono_metadata_free_mh (cheader);
6429                 return 0;
6430         }
6431
6432         /* allocate space to store the return value */
6433         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6434                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6435         }
6436
6437         prev_locals = cfg->locals;
6438         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
6439         for (i = 0; i < cheader->num_locals; ++i)
6440                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6441
6442         /* allocate start and end blocks */
6443         /* This is needed so if the inline is aborted, we can clean up */
6444         NEW_BBLOCK (cfg, sbblock);
6445         sbblock->real_offset = real_offset;
6446
6447         NEW_BBLOCK (cfg, ebblock);
6448         ebblock->block_num = cfg->num_bblocks++;
6449         ebblock->real_offset = real_offset;
6450
6451         prev_args = cfg->args;
6452         prev_arg_types = cfg->arg_types;
6453         prev_inlined_method = cfg->inlined_method;
6454         cfg->inlined_method = cmethod;
6455         cfg->ret_var_set = FALSE;
6456         cfg->inline_depth ++;
6457         prev_real_offset = cfg->real_offset;
6458         prev_cbb_hash = cfg->cbb_hash;
6459         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6460         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6461         prev_cil_start = cfg->cil_start;
6462         prev_ip = cfg->ip;
6463         prev_cbb = cfg->cbb;
6464         prev_current_method = cfg->current_method;
6465         prev_generic_context = cfg->generic_context;
6466         prev_ret_var_set = cfg->ret_var_set;
6467         prev_disable_inline = cfg->disable_inline;
6468
6469         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6470                 virtual_ = TRUE;
6471
6472         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
6473
6474         ret_var_set = cfg->ret_var_set;
6475
6476         cfg->inlined_method = prev_inlined_method;
6477         cfg->real_offset = prev_real_offset;
6478         cfg->cbb_hash = prev_cbb_hash;
6479         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6480         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6481         cfg->cil_start = prev_cil_start;
6482         cfg->ip = prev_ip;
6483         cfg->locals = prev_locals;
6484         cfg->args = prev_args;
6485         cfg->arg_types = prev_arg_types;
6486         cfg->current_method = prev_current_method;
6487         cfg->generic_context = prev_generic_context;
6488         cfg->ret_var_set = prev_ret_var_set;
6489         cfg->disable_inline = prev_disable_inline;
6490         cfg->inline_depth --;
6491
6492         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
6493                 if (cfg->verbose_level > 2)
6494                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6495
6496                 cfg->stat_inlined_methods++;
6497
6498                 /* always add some code to avoid block split failures */
6499                 MONO_INST_NEW (cfg, ins, OP_NOP);
6500                 MONO_ADD_INS (prev_cbb, ins);
6501
6502                 prev_cbb->next_bb = sbblock;
6503                 link_bblock (cfg, prev_cbb, sbblock);
6504
6505                 /* 
6506                  * Get rid of the begin and end bblocks if possible to aid local
6507                  * optimizations.
6508                  */
6509                 if (prev_cbb->out_count == 1)
6510                         mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6511
6512                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6513                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6514
6515                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6516                         MonoBasicBlock *prev = ebblock->in_bb [0];
6517
6518                         if (prev->next_bb == ebblock) {
6519                                 mono_merge_basic_blocks (cfg, prev, ebblock);
6520                                 cfg->cbb = prev;
6521                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6522                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
6523                                         cfg->cbb = prev_cbb;
6524                                 }
6525                         } else {
6526                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
6527                                 cfg->cbb = ebblock;
6528                         }
6529                 } else {
6530                         /* 
6531                          * Its possible that the rvar is set in some prev bblock, but not in others.
6532                          * (#1835).
6533                          */
6534                         if (rvar) {
6535                                 MonoBasicBlock *bb;
6536
6537                                 for (i = 0; i < ebblock->in_count; ++i) {
6538                                         bb = ebblock->in_bb [i];
6539
6540                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6541                                                 cfg->cbb = bb;
6542
6543                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6544                                         }
6545                                 }
6546                         }
6547
6548                         cfg->cbb = ebblock;
6549                 }
6550
6551                 if (rvar) {
6552                         /*
6553                          * If the inlined method contains only a throw, then the ret var is not 
6554                          * set, so set it to a dummy value.
6555                          */
6556                         if (!ret_var_set)
6557                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6558
6559                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6560                         *sp++ = ins;
6561                 }
6562                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6563                 return costs + 1;
6564         } else {
6565                 if (cfg->verbose_level > 2)
6566                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6567                 cfg->exception_type = MONO_EXCEPTION_NONE;
6568
6569                 /* This gets rid of the newly added bblocks */
6570                 cfg->cbb = prev_cbb;
6571         }
6572         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6573         return 0;
6574 }
6575
6576 /*
6577  * Some of these comments may well be out-of-date.
6578  * Design decisions: we do a single pass over the IL code (and we do bblock 
6579  * splitting/merging in the few cases when it's required: a back jump to an IL
6580  * address that was not already seen as bblock starting point).
6581  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6582  * Complex operations are decomposed in simpler ones right away. We need to let the 
6583  * arch-specific code peek and poke inside this process somehow (except when the 
6584  * optimizations can take advantage of the full semantic info of coarse opcodes).
6585  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6586  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6587  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6588  * opcode with value bigger than OP_LAST.
6589  * At this point the IR can be handed over to an interpreter, a dumb code generator
6590  * or to the optimizing code generator that will translate it to SSA form.
6591  *
6592  * Profiling directed optimizations.
6593  * We may compile by default with few or no optimizations and instrument the code
6594  * or the user may indicate what methods to optimize the most either in a config file
6595  * or through repeated runs where the compiler applies offline the optimizations to 
6596  * each method and then decides if it was worth it.
6597  */
6598
6599 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6600 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6601 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6602 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6603 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6604 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6605 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6606 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
6607
6608 /* offset from br.s -> br like opcodes */
6609 #define BIG_BRANCH_OFFSET 13
6610
6611 static gboolean
6612 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6613 {
6614         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6615
6616         return b == NULL || b == bb;
6617 }
6618
6619 static int
6620 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6621 {
6622         unsigned char *ip = start;
6623         unsigned char *target;
6624         int i;
6625         guint cli_addr;
6626         MonoBasicBlock *bblock;
6627         const MonoOpcode *opcode;
6628
6629         while (ip < end) {
6630                 cli_addr = ip - start;
6631                 i = mono_opcode_value ((const guint8 **)&ip, end);
6632                 if (i < 0)
6633                         UNVERIFIED;
6634                 opcode = &mono_opcodes [i];
6635                 switch (opcode->argument) {
6636                 case MonoInlineNone:
6637                         ip++; 
6638                         break;
6639                 case MonoInlineString:
6640                 case MonoInlineType:
6641                 case MonoInlineField:
6642                 case MonoInlineMethod:
6643                 case MonoInlineTok:
6644                 case MonoInlineSig:
6645                 case MonoShortInlineR:
6646                 case MonoInlineI:
6647                         ip += 5;
6648                         break;
6649                 case MonoInlineVar:
6650                         ip += 3;
6651                         break;
6652                 case MonoShortInlineVar:
6653                 case MonoShortInlineI:
6654                         ip += 2;
6655                         break;
6656                 case MonoShortInlineBrTarget:
6657                         target = start + cli_addr + 2 + (signed char)ip [1];
6658                         GET_BBLOCK (cfg, bblock, target);
6659                         ip += 2;
6660                         if (ip < end)
6661                                 GET_BBLOCK (cfg, bblock, ip);
6662                         break;
6663                 case MonoInlineBrTarget:
6664                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6665                         GET_BBLOCK (cfg, bblock, target);
6666                         ip += 5;
6667                         if (ip < end)
6668                                 GET_BBLOCK (cfg, bblock, ip);
6669                         break;
6670                 case MonoInlineSwitch: {
6671                         guint32 n = read32 (ip + 1);
6672                         guint32 j;
6673                         ip += 5;
6674                         cli_addr += 5 + 4 * n;
6675                         target = start + cli_addr;
6676                         GET_BBLOCK (cfg, bblock, target);
6677                         
6678                         for (j = 0; j < n; ++j) {
6679                                 target = start + cli_addr + (gint32)read32 (ip);
6680                                 GET_BBLOCK (cfg, bblock, target);
6681                                 ip += 4;
6682                         }
6683                         break;
6684                 }
6685                 case MonoInlineR:
6686                 case MonoInlineI8:
6687                         ip += 9;
6688                         break;
6689                 default:
6690                         g_assert_not_reached ();
6691                 }
6692
6693                 if (i == CEE_THROW) {
6694                         unsigned char *bb_start = ip - 1;
6695                         
6696                         /* Find the start of the bblock containing the throw */
6697                         bblock = NULL;
6698                         while ((bb_start >= start) && !bblock) {
6699                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6700                                 bb_start --;
6701                         }
6702                         if (bblock)
6703                                 bblock->out_of_line = 1;
6704                 }
6705         }
6706         return 0;
6707 unverified:
6708 exception_exit:
6709         *pos = ip;
6710         return 1;
6711 }
6712
6713 static inline MonoMethod *
6714 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
6715 {
6716         MonoMethod *method;
6717
6718         mono_error_init (error);
6719
6720         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6721                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
6722                 if (context) {
6723                         method = mono_class_inflate_generic_method_checked (method, context, error);
6724                 }
6725         } else {
6726                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
6727         }
6728
6729         return method;
6730 }
6731
6732 static inline MonoMethod *
6733 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6734 {
6735         MonoError error;
6736         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
6737
6738         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
6739                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
6740                 method = NULL;
6741         }
6742
6743         if (!method && !cfg)
6744                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6745
6746         return method;
6747 }
6748
6749 static inline MonoClass*
6750 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6751 {
6752         MonoError error;
6753         MonoClass *klass;
6754
6755         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6756                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
6757                 if (context) {
6758                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
6759                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6760                 }
6761         } else {
6762                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
6763                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6764         }
6765         if (klass)
6766                 mono_class_init (klass);
6767         return klass;
6768 }
6769
6770 static inline MonoMethodSignature*
6771 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
6772 {
6773         MonoMethodSignature *fsig;
6774
6775         mono_error_init (error);
6776         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6777                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6778         } else {
6779                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
6780                 return_val_if_nok (error, NULL);
6781         }
6782         if (context) {
6783                 fsig = mono_inflate_generic_signature(fsig, context, error);
6784         }
6785         return fsig;
6786 }
6787
6788 static MonoMethod*
6789 throw_exception (void)
6790 {
6791         static MonoMethod *method = NULL;
6792
6793         if (!method) {
6794                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6795                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6796         }
6797         g_assert (method);
6798         return method;
6799 }
6800
6801 static void
6802 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6803 {
6804         MonoMethod *thrower = throw_exception ();
6805         MonoInst *args [1];
6806
6807         EMIT_NEW_PCONST (cfg, args [0], ex);
6808         mono_emit_method_call (cfg, thrower, args, NULL);
6809 }
6810
6811 /*
6812  * Return the original method is a wrapper is specified. We can only access 
6813  * the custom attributes from the original method.
6814  */
6815 static MonoMethod*
6816 get_original_method (MonoMethod *method)
6817 {
6818         if (method->wrapper_type == MONO_WRAPPER_NONE)
6819                 return method;
6820
6821         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6822         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6823                 return NULL;
6824
6825         /* in other cases we need to find the original method */
6826         return mono_marshal_method_from_wrapper (method);
6827 }
6828
6829 static void
6830 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
6831 {
6832         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6833         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6834         if (ex)
6835                 emit_throw_exception (cfg, ex);
6836 }
6837
6838 static void
6839 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6840 {
6841         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6842         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6843         if (ex)
6844                 emit_throw_exception (cfg, ex);
6845 }
6846
6847 /*
6848  * Check that the IL instructions at ip are the array initialization
6849  * sequence and return the pointer to the data and the size.
6850  */
6851 static const char*
6852 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6853 {
6854         /*
6855          * newarr[System.Int32]
6856          * dup
6857          * ldtoken field valuetype ...
6858          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6859          */
6860         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6861                 MonoError error;
6862                 guint32 token = read32 (ip + 7);
6863                 guint32 field_token = read32 (ip + 2);
6864                 guint32 field_index = field_token & 0xffffff;
6865                 guint32 rva;
6866                 const char *data_ptr;
6867                 int size = 0;
6868                 MonoMethod *cmethod;
6869                 MonoClass *dummy_class;
6870                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
6871                 int dummy_align;
6872
6873                 if (!field) {
6874                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6875                         return NULL;
6876                 }
6877
6878                 *out_field_token = field_token;
6879
6880                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6881                 if (!cmethod)
6882                         return NULL;
6883                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6884                         return NULL;
6885                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6886                 case MONO_TYPE_BOOLEAN:
6887                 case MONO_TYPE_I1:
6888                 case MONO_TYPE_U1:
6889                         size = 1; break;
6890                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6891 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6892                 case MONO_TYPE_CHAR:
6893                 case MONO_TYPE_I2:
6894                 case MONO_TYPE_U2:
6895                         size = 2; break;
6896                 case MONO_TYPE_I4:
6897                 case MONO_TYPE_U4:
6898                 case MONO_TYPE_R4:
6899                         size = 4; break;
6900                 case MONO_TYPE_R8:
6901                 case MONO_TYPE_I8:
6902                 case MONO_TYPE_U8:
6903                         size = 8; break;
6904 #endif
6905                 default:
6906                         return NULL;
6907                 }
6908                 size *= len;
6909                 if (size > mono_type_size (field->type, &dummy_align))
6910                     return NULL;
6911                 *out_size = size;
6912                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6913                 if (!image_is_dynamic (method->klass->image)) {
6914                         field_index = read32 (ip + 2) & 0xffffff;
6915                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6916                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6917                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6918                         /* for aot code we do the lookup on load */
6919                         if (aot && data_ptr)
6920                                 return (const char *)GUINT_TO_POINTER (rva);
6921                 } else {
6922                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6923                         g_assert (!aot);
6924                         data_ptr = mono_field_get_data (field);
6925                 }
6926                 return data_ptr;
6927         }
6928         return NULL;
6929 }
6930
6931 static void
6932 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6933 {
6934         MonoError error;
6935         char *method_fname = mono_method_full_name (method, TRUE);
6936         char *method_code;
6937         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
6938
6939         if (!header) {
6940                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
6941                 mono_error_cleanup (&error);
6942         } else if (header->code_size == 0)
6943                 method_code = g_strdup ("method body is empty.");
6944         else
6945                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6946         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
6947         g_free (method_fname);
6948         g_free (method_code);
6949         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6950 }
6951
6952 static void
6953 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6954 {
6955         MonoInst *ins;
6956         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6957         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6958                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6959                 /* Optimize reg-reg moves away */
6960                 /* 
6961                  * Can't optimize other opcodes, since sp[0] might point to
6962                  * the last ins of a decomposed opcode.
6963                  */
6964                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6965         } else {
6966                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6967         }
6968 }
6969
6970 /*
6971  * ldloca inhibits many optimizations so try to get rid of it in common
6972  * cases.
6973  */
6974 static inline unsigned char *
6975 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6976 {
6977         int local, token;
6978         MonoClass *klass;
6979         MonoType *type;
6980
6981         if (size == 1) {
6982                 local = ip [1];
6983                 ip += 2;
6984         } else {
6985                 local = read16 (ip + 2);
6986                 ip += 4;
6987         }
6988         
6989         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6990                 /* From the INITOBJ case */
6991                 token = read32 (ip + 2);
6992                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6993                 CHECK_TYPELOAD (klass);
6994                 type = mini_get_underlying_type (&klass->byval_arg);
6995                 emit_init_local (cfg, local, type, TRUE);
6996                 return ip + 6;
6997         }
6998  exception_exit:
6999         return NULL;
7000 }
7001
7002 static MonoInst*
7003 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7004 {
7005         MonoInst *icall_args [16];
7006         MonoInst *call_target, *ins, *vtable_ins;
7007         int arg_reg, this_reg, vtable_reg;
7008         gboolean is_iface = mono_class_is_interface (cmethod->klass);
7009         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7010         gboolean variant_iface = FALSE;
7011         guint32 slot;
7012         int offset;
7013         gboolean special_array_interface = cmethod->klass->is_array_special_interface;
7014
7015         /*
7016          * In llvm-only mode, vtables contain function descriptors instead of
7017          * method addresses/trampolines.
7018          */
7019         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7020
7021         if (is_iface)
7022                 slot = mono_method_get_imt_slot (cmethod);
7023         else
7024                 slot = mono_method_get_vtable_index (cmethod);
7025
7026         this_reg = sp [0]->dreg;
7027
7028         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7029                 variant_iface = TRUE;
7030
7031         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7032                 /*
7033                  * The simplest case, a normal virtual call.
7034                  */
7035                 int slot_reg = alloc_preg (cfg);
7036                 int addr_reg = alloc_preg (cfg);
7037                 int arg_reg = alloc_preg (cfg);
7038                 MonoBasicBlock *non_null_bb;
7039
7040                 vtable_reg = alloc_preg (cfg);
7041                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7042                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7043
7044                 /* Load the vtable slot, which contains a function descriptor. */
7045                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7046
7047                 NEW_BBLOCK (cfg, non_null_bb);
7048
7049                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7050                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7051                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7052
7053                 /* Slow path */
7054                 // FIXME: Make the wrapper use the preserveall cconv
7055                 // FIXME: Use one icall per slot for small slot numbers ?
7056                 icall_args [0] = vtable_ins;
7057                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7058                 /* Make the icall return the vtable slot value to save some code space */
7059                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7060                 ins->dreg = slot_reg;
7061                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7062
7063                 /* Fastpath */
7064                 MONO_START_BB (cfg, non_null_bb);
7065                 /* Load the address + arg from the vtable slot */
7066                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7067                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7068
7069                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7070         }
7071
7072         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt && !special_array_interface) {
7073                 /*
7074                  * A simple interface call
7075                  *
7076                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7077                  * The imt slot contains a function descriptor for a runtime function + arg.
7078                  */
7079                 int slot_reg = alloc_preg (cfg);
7080                 int addr_reg = alloc_preg (cfg);
7081                 int arg_reg = alloc_preg (cfg);
7082                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7083
7084                 vtable_reg = alloc_preg (cfg);
7085                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7086                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7087
7088                 /*
7089                  * The slot is already initialized when the vtable is created so there is no need
7090                  * to check it here.
7091                  */
7092
7093                 /* Load the imt slot, which contains a function descriptor. */
7094                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7095
7096                 /* Load the address + arg of the imt thunk from the imt slot */
7097                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7098                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7099                 /*
7100                  * IMT thunks in llvm-only mode are C functions which take an info argument
7101                  * plus the imt method and return the ftndesc to call.
7102                  */
7103                 icall_args [0] = thunk_arg_ins;
7104                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7105                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7106                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7107
7108                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7109         }
7110
7111         if ((fsig->generic_param_count || variant_iface || special_array_interface) && !is_gsharedvt) {
7112                 /*
7113                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7114                  * dynamically extended as more instantiations are discovered.
7115                  * This handles generic virtual methods both on classes and interfaces.
7116                  */
7117                 int slot_reg = alloc_preg (cfg);
7118                 int addr_reg = alloc_preg (cfg);
7119                 int arg_reg = alloc_preg (cfg);
7120                 int ftndesc_reg = alloc_preg (cfg);
7121                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7122                 MonoBasicBlock *slowpath_bb, *end_bb;
7123
7124                 NEW_BBLOCK (cfg, slowpath_bb);
7125                 NEW_BBLOCK (cfg, end_bb);
7126
7127                 vtable_reg = alloc_preg (cfg);
7128                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7129                 if (is_iface)
7130                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7131                 else
7132                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7133
7134                 /* Load the slot, which contains a function descriptor. */
7135                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7136
7137                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7138                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7139                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7140                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7141
7142                 /* Fastpath */
7143                 /* Same as with iface calls */
7144                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7145                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7146                 icall_args [0] = thunk_arg_ins;
7147                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7148                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7149                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7150                 ftndesc_ins->dreg = ftndesc_reg;
7151                 /*
7152                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7153                  * they don't know about yet. Fall back to the slowpath in that case.
7154                  */
7155                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7156                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7157
7158                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7159
7160                 /* Slowpath */
7161                 MONO_START_BB (cfg, slowpath_bb);
7162                 icall_args [0] = vtable_ins;
7163                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7164                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7165                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7166                 if (is_iface)
7167                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7168                 else
7169                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7170                 ftndesc_ins->dreg = ftndesc_reg;
7171                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7172
7173                 /* Common case */
7174                 MONO_START_BB (cfg, end_bb);
7175                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7176         }
7177
7178         /*
7179          * Non-optimized cases
7180          */
7181         icall_args [0] = sp [0];
7182         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7183
7184         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7185                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7186
7187         arg_reg = alloc_preg (cfg);
7188         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7189         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7190
7191         g_assert (is_gsharedvt);
7192         if (is_iface)
7193                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7194         else
7195                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7196
7197         /*
7198          * Pass the extra argument even if the callee doesn't receive it, most
7199          * calling conventions allow this.
7200          */
7201         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7202 }
7203
7204 static gboolean
7205 is_exception_class (MonoClass *klass)
7206 {
7207         while (klass) {
7208                 if (klass == mono_defaults.exception_class)
7209                         return TRUE;
7210                 klass = klass->parent;
7211         }
7212         return FALSE;
7213 }
7214
7215 /*
7216  * is_jit_optimizer_disabled:
7217  *
7218  *   Determine whenever M's assembly has a DebuggableAttribute with the
7219  * IsJITOptimizerDisabled flag set.
7220  */
7221 static gboolean
7222 is_jit_optimizer_disabled (MonoMethod *m)
7223 {
7224         MonoError error;
7225         MonoAssembly *ass = m->klass->image->assembly;
7226         MonoCustomAttrInfo* attrs;
7227         MonoClass *klass;
7228         int i;
7229         gboolean val = FALSE;
7230
7231         g_assert (ass);
7232         if (ass->jit_optimizer_disabled_inited)
7233                 return ass->jit_optimizer_disabled;
7234
7235         klass = mono_class_try_get_debuggable_attribute_class ();
7236
7237         if (!klass) {
7238                 /* Linked away */
7239                 ass->jit_optimizer_disabled = FALSE;
7240                 mono_memory_barrier ();
7241                 ass->jit_optimizer_disabled_inited = TRUE;
7242                 return FALSE;
7243         }
7244
7245         attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
7246         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7247         if (attrs) {
7248                 for (i = 0; i < attrs->num_attrs; ++i) {
7249                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7250                         const gchar *p;
7251                         MonoMethodSignature *sig;
7252
7253                         if (!attr->ctor || attr->ctor->klass != klass)
7254                                 continue;
7255                         /* Decode the attribute. See reflection.c */
7256                         p = (const char*)attr->data;
7257                         g_assert (read16 (p) == 0x0001);
7258                         p += 2;
7259
7260                         // FIXME: Support named parameters
7261                         sig = mono_method_signature (attr->ctor);
7262                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7263                                 continue;
7264                         /* Two boolean arguments */
7265                         p ++;
7266                         val = *p;
7267                 }
7268                 mono_custom_attrs_free (attrs);
7269         }
7270
7271         ass->jit_optimizer_disabled = val;
7272         mono_memory_barrier ();
7273         ass->jit_optimizer_disabled_inited = TRUE;
7274
7275         return val;
7276 }
7277
7278 static gboolean
7279 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7280 {
7281         gboolean supported_tail_call;
7282         int i;
7283
7284         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7285
7286         for (i = 0; i < fsig->param_count; ++i) {
7287                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7288                         /* These can point to the current method's stack */
7289                         supported_tail_call = FALSE;
7290         }
7291         if (fsig->hasthis && cmethod->klass->valuetype)
7292                 /* this might point to the current method's stack */
7293                 supported_tail_call = FALSE;
7294         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7295                 supported_tail_call = FALSE;
7296         if (cfg->method->save_lmf)
7297                 supported_tail_call = FALSE;
7298         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7299                 supported_tail_call = FALSE;
7300         if (call_opcode != CEE_CALL)
7301                 supported_tail_call = FALSE;
7302
7303         /* Debugging support */
7304 #if 0
7305         if (supported_tail_call) {
7306                 if (!mono_debug_count ())
7307                         supported_tail_call = FALSE;
7308         }
7309 #endif
7310
7311         return supported_tail_call;
7312 }
7313
7314 /*
7315  * handle_ctor_call:
7316  *
7317  *   Handle calls made to ctors from NEWOBJ opcodes.
7318  */
7319 static void
7320 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7321                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7322 {
7323         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7324
7325         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7326                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7327                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7328                         mono_class_vtable (cfg->domain, cmethod->klass);
7329                         CHECK_TYPELOAD (cmethod->klass);
7330
7331                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7332                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7333                 } else {
7334                         if (context_used) {
7335                                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
7336                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7337                         } else {
7338                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7339
7340                                 CHECK_TYPELOAD (cmethod->klass);
7341                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7342                         }
7343                 }
7344         }
7345
7346         /* Avoid virtual calls to ctors if possible */
7347         if (mono_class_is_marshalbyref (cmethod->klass))
7348                 callvirt_this_arg = sp [0];
7349
7350         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7351                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7352                 CHECK_CFG_EXCEPTION;
7353         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7354                            mono_method_check_inlining (cfg, cmethod) &&
7355                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7356                 int costs;
7357
7358                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7359                         cfg->real_offset += 5;
7360
7361                         *inline_costs += costs - 5;
7362                 } else {
7363                         INLINE_FAILURE ("inline failure");
7364                         // FIXME-VT: Clean this up
7365                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7366                                 GSHAREDVT_FAILURE(*ip);
7367                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7368                 }
7369         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7370                 MonoInst *addr;
7371
7372                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7373
7374                 if (cfg->llvm_only) {
7375                         // FIXME: Avoid initializing vtable_arg
7376                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7377                 } else {
7378                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7379                 }
7380         } else if (context_used &&
7381                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7382                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7383                 MonoInst *cmethod_addr;
7384
7385                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7386
7387                 if (cfg->llvm_only) {
7388                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
7389                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7390                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7391                 } else {
7392                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7393                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7394
7395                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7396                 }
7397         } else {
7398                 INLINE_FAILURE ("ctor call");
7399                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7400                                                                                   callvirt_this_arg, NULL, vtable_arg);
7401         }
7402  exception_exit:
7403         return;
7404 }
7405
7406 static void
7407 emit_setret (MonoCompile *cfg, MonoInst *val)
7408 {
7409         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7410         MonoInst *ins;
7411
7412         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7413                 MonoInst *ret_addr;
7414
7415                 if (!cfg->vret_addr) {
7416                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7417                 } else {
7418                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7419
7420                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7421                         ins->klass = mono_class_from_mono_type (ret_type);
7422                 }
7423         } else {
7424 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7425                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7426                         MonoInst *iargs [1];
7427                         MonoInst *conv;
7428
7429                         iargs [0] = val;
7430                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7431                         mono_arch_emit_setret (cfg, cfg->method, conv);
7432                 } else {
7433                         mono_arch_emit_setret (cfg, cfg->method, val);
7434                 }
7435 #else
7436                 mono_arch_emit_setret (cfg, cfg->method, val);
7437 #endif
7438         }
7439 }
7440
7441 /*
7442  * mono_method_to_ir:
7443  *
7444  * Translate the .net IL into linear IR.
7445  *
7446  * @start_bblock: if not NULL, the starting basic block, used during inlining.
7447  * @end_bblock: if not NULL, the ending basic block, used during inlining.
7448  * @return_var: if not NULL, the place where the return value is stored, used during inlining.   
7449  * @inline_args: if not NULL, contains the arguments to the inline call
7450  * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise.
7451  * @is_virtual_call: whether this method is being called as a result of a call to callvirt
7452  *
7453  * This method is used to turn ECMA IL into Mono's internal Linear IR
7454  * reprensetation.  It is used both for entire methods, as well as
7455  * inlining existing methods.  In the former case, the @start_bblock,
7456  * @end_bblock, @return_var, @inline_args are all set to NULL, and the
7457  * inline_offset is set to zero.
7458  * 
7459  * Returns: the inline cost, or -1 if there was an error processing this method.
7460  */
7461 int
7462 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7463                    MonoInst *return_var, MonoInst **inline_args, 
7464                    guint inline_offset, gboolean is_virtual_call)
7465 {
7466         MonoError error;
7467         MonoInst *ins, **sp, **stack_start;
7468         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7469         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7470         MonoMethod *cmethod, *method_definition;
7471         MonoInst **arg_array;
7472         MonoMethodHeader *header;
7473         MonoImage *image;
7474         guint32 token, ins_flag;
7475         MonoClass *klass;
7476         MonoClass *constrained_class = NULL;
7477         unsigned char *ip, *end, *target, *err_pos;
7478         MonoMethodSignature *sig;
7479         MonoGenericContext *generic_context = NULL;
7480         MonoGenericContainer *generic_container = NULL;
7481         MonoType **param_types;
7482         int i, n, start_new_bblock, dreg;
7483         int num_calls = 0, inline_costs = 0;
7484         int breakpoint_id = 0;
7485         guint num_args;
7486         GSList *class_inits = NULL;
7487         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7488         int context_used;
7489         gboolean init_locals, seq_points, skip_dead_blocks;
7490         gboolean sym_seq_points = FALSE;
7491         MonoDebugMethodInfo *minfo;
7492         MonoBitSet *seq_point_locs = NULL;
7493         MonoBitSet *seq_point_set_locs = NULL;
7494
7495         cfg->disable_inline = is_jit_optimizer_disabled (method);
7496
7497         /* serialization and xdomain stuff may need access to private fields and methods */
7498         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7499         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7500         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7501         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7502         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7503         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7504
7505         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7506         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7507         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7508         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7509         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7510
7511         image = method->klass->image;
7512         header = mono_method_get_header_checked (method, &cfg->error);
7513         if (!header) {
7514                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7515                 goto exception_exit;
7516         } else {
7517                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7518         }
7519
7520         generic_container = mono_method_get_generic_container (method);
7521         sig = mono_method_signature (method);
7522         num_args = sig->hasthis + sig->param_count;
7523         ip = (unsigned char*)header->code;
7524         cfg->cil_start = ip;
7525         end = ip + header->code_size;
7526         cfg->stat_cil_code_size += header->code_size;
7527
7528         seq_points = cfg->gen_seq_points && cfg->method == method;
7529
7530         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7531                 /* We could hit a seq point before attaching to the JIT (#8338) */
7532                 seq_points = FALSE;
7533         }
7534
7535         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7536                 minfo = mono_debug_lookup_method (method);
7537                 if (minfo) {
7538                         MonoSymSeqPoint *sps;
7539                         int i, n_il_offsets;
7540
7541                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7542                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7543                         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);
7544                         sym_seq_points = TRUE;
7545                         for (i = 0; i < n_il_offsets; ++i) {
7546                                 if (sps [i].il_offset < header->code_size)
7547                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7548                         }
7549                         g_free (sps);
7550                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7551                         /* Methods without line number info like auto-generated property accessors */
7552                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7553                         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);
7554                         sym_seq_points = TRUE;
7555                 }
7556         }
7557
7558         /* 
7559          * Methods without init_locals set could cause asserts in various passes
7560          * (#497220). To work around this, we emit dummy initialization opcodes
7561          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7562          * on some platforms.
7563          */
7564         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
7565                 init_locals = header->init_locals;
7566         else
7567                 init_locals = TRUE;
7568
7569         method_definition = method;
7570         while (method_definition->is_inflated) {
7571                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7572                 method_definition = imethod->declaring;
7573         }
7574
7575         /* SkipVerification is not allowed if core-clr is enabled */
7576         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7577                 dont_verify = TRUE;
7578                 dont_verify_stloc = TRUE;
7579         }
7580
7581         if (sig->is_inflated)
7582                 generic_context = mono_method_get_context (method);
7583         else if (generic_container)
7584                 generic_context = &generic_container->context;
7585         cfg->generic_context = generic_context;
7586
7587         if (!cfg->gshared)
7588                 g_assert (!sig->has_type_parameters);
7589
7590         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7591                 g_assert (method->is_inflated);
7592                 g_assert (mono_method_get_context (method)->method_inst);
7593         }
7594         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7595                 g_assert (sig->generic_param_count);
7596
7597         if (cfg->method == method) {
7598                 cfg->real_offset = 0;
7599         } else {
7600                 cfg->real_offset = inline_offset;
7601         }
7602
7603         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7604         cfg->cil_offset_to_bb_len = header->code_size;
7605
7606         cfg->current_method = method;
7607
7608         if (cfg->verbose_level > 2)
7609                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7610
7611         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7612         if (sig->hasthis)
7613                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7614         for (n = 0; n < sig->param_count; ++n)
7615                 param_types [n + sig->hasthis] = sig->params [n];
7616         cfg->arg_types = param_types;
7617
7618         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7619         if (cfg->method == method) {
7620
7621                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7622                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7623
7624                 /* ENTRY BLOCK */
7625                 NEW_BBLOCK (cfg, start_bblock);
7626                 cfg->bb_entry = start_bblock;
7627                 start_bblock->cil_code = NULL;
7628                 start_bblock->cil_length = 0;
7629
7630                 /* EXIT BLOCK */
7631                 NEW_BBLOCK (cfg, end_bblock);
7632                 cfg->bb_exit = end_bblock;
7633                 end_bblock->cil_code = NULL;
7634                 end_bblock->cil_length = 0;
7635                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7636                 g_assert (cfg->num_bblocks == 2);
7637
7638                 arg_array = cfg->args;
7639
7640                 if (header->num_clauses) {
7641                         cfg->spvars = g_hash_table_new (NULL, NULL);
7642                         cfg->exvars = g_hash_table_new (NULL, NULL);
7643                 }
7644                 /* handle exception clauses */
7645                 for (i = 0; i < header->num_clauses; ++i) {
7646                         MonoBasicBlock *try_bb;
7647                         MonoExceptionClause *clause = &header->clauses [i];
7648                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7649
7650                         try_bb->real_offset = clause->try_offset;
7651                         try_bb->try_start = TRUE;
7652                         try_bb->region = ((i + 1) << 8) | clause->flags;
7653                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7654                         tblock->real_offset = clause->handler_offset;
7655                         tblock->flags |= BB_EXCEPTION_HANDLER;
7656
7657                         /*
7658                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7659                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7660                          */
7661                         if (COMPILE_LLVM (cfg))
7662                                 link_bblock (cfg, try_bb, tblock);
7663
7664                         if (*(ip + clause->handler_offset) == CEE_POP)
7665                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7666
7667                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7668                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7669                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7670                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7671                                 MONO_ADD_INS (tblock, ins);
7672
7673                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
7674                                         /* finally clauses already have a seq point */
7675                                         /* seq points for filter clauses are emitted below */
7676                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7677                                         MONO_ADD_INS (tblock, ins);
7678                                 }
7679
7680                                 /* todo: is a fault block unsafe to optimize? */
7681                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7682                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7683                         }
7684
7685                         /*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);
7686                           while (p < end) {
7687                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7688                           }*/
7689                         /* catch and filter blocks get the exception object on the stack */
7690                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7691                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7692
7693                                 /* mostly like handle_stack_args (), but just sets the input args */
7694                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7695                                 tblock->in_scount = 1;
7696                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7697                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7698
7699                                 cfg->cbb = tblock;
7700
7701 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7702                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7703                                 if (!cfg->compile_llvm) {
7704                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7705                                         ins->dreg = tblock->in_stack [0]->dreg;
7706                                         MONO_ADD_INS (tblock, ins);
7707                                 }
7708 #else
7709                                 MonoInst *dummy_use;
7710
7711                                 /* 
7712                                  * Add a dummy use for the exvar so its liveness info will be
7713                                  * correct.
7714                                  */
7715                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7716 #endif
7717
7718                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7719                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7720                                         MONO_ADD_INS (tblock, ins);
7721                                 }
7722                                 
7723                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7724                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7725                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7726                                         tblock->real_offset = clause->data.filter_offset;
7727                                         tblock->in_scount = 1;
7728                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7729                                         /* The filter block shares the exvar with the handler block */
7730                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7731                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7732                                         MONO_ADD_INS (tblock, ins);
7733                                 }
7734                         }
7735
7736                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7737                                         clause->data.catch_class &&
7738                                         cfg->gshared &&
7739                                         mono_class_check_context_used (clause->data.catch_class)) {
7740                                 /*
7741                                  * In shared generic code with catch
7742                                  * clauses containing type variables
7743                                  * the exception handling code has to
7744                                  * be able to get to the rgctx.
7745                                  * Therefore we have to make sure that
7746                                  * the vtable/mrgctx argument (for
7747                                  * static or generic methods) or the
7748                                  * "this" argument (for non-static
7749                                  * methods) are live.
7750                                  */
7751                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7752                                                 mini_method_get_context (method)->method_inst ||
7753                                                 method->klass->valuetype) {
7754                                         mono_get_vtable_var (cfg);
7755                                 } else {
7756                                         MonoInst *dummy_use;
7757
7758                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7759                                 }
7760                         }
7761                 }
7762         } else {
7763                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7764                 cfg->cbb = start_bblock;
7765                 cfg->args = arg_array;
7766                 mono_save_args (cfg, sig, inline_args);
7767         }
7768
7769         /* FIRST CODE BLOCK */
7770         NEW_BBLOCK (cfg, tblock);
7771         tblock->cil_code = ip;
7772         cfg->cbb = tblock;
7773         cfg->ip = ip;
7774
7775         ADD_BBLOCK (cfg, tblock);
7776
7777         if (cfg->method == method) {
7778                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7779                 if (breakpoint_id) {
7780                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7781                         MONO_ADD_INS (cfg->cbb, ins);
7782                 }
7783         }
7784
7785         /* we use a separate basic block for the initialization code */
7786         NEW_BBLOCK (cfg, init_localsbb);
7787         if (cfg->method == method)
7788                 cfg->bb_init = init_localsbb;
7789         init_localsbb->real_offset = cfg->real_offset;
7790         start_bblock->next_bb = init_localsbb;
7791         init_localsbb->next_bb = cfg->cbb;
7792         link_bblock (cfg, start_bblock, init_localsbb);
7793         link_bblock (cfg, init_localsbb, cfg->cbb);
7794                 
7795         cfg->cbb = init_localsbb;
7796
7797         if (cfg->gsharedvt && cfg->method == method) {
7798                 MonoGSharedVtMethodInfo *info;
7799                 MonoInst *var, *locals_var;
7800                 int dreg;
7801
7802                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7803                 info->method = cfg->method;
7804                 info->count_entries = 16;
7805                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7806                 cfg->gsharedvt_info = info;
7807
7808                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7809                 /* prevent it from being register allocated */
7810                 //var->flags |= MONO_INST_VOLATILE;
7811                 cfg->gsharedvt_info_var = var;
7812
7813                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7814                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7815
7816                 /* Allocate locals */
7817                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7818                 /* prevent it from being register allocated */
7819                 //locals_var->flags |= MONO_INST_VOLATILE;
7820                 cfg->gsharedvt_locals_var = locals_var;
7821
7822                 dreg = alloc_ireg (cfg);
7823                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7824
7825                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7826                 ins->dreg = locals_var->dreg;
7827                 ins->sreg1 = dreg;
7828                 MONO_ADD_INS (cfg->cbb, ins);
7829                 cfg->gsharedvt_locals_var_ins = ins;
7830                 
7831                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7832                 /*
7833                 if (init_locals)
7834                         ins->flags |= MONO_INST_INIT;
7835                 */
7836         }
7837
7838         if (mono_security_core_clr_enabled ()) {
7839                 /* check if this is native code, e.g. an icall or a p/invoke */
7840                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7841                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7842                         if (wrapped) {
7843                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7844                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7845
7846                                 /* if this ia a native call then it can only be JITted from platform code */
7847                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7848                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7849                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7850                                                         mono_get_exception_method_access ();
7851                                                 emit_throw_exception (cfg, ex);
7852                                         }
7853                                 }
7854                         }
7855                 }
7856         }
7857
7858         CHECK_CFG_EXCEPTION;
7859
7860         if (header->code_size == 0)
7861                 UNVERIFIED;
7862
7863         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7864                 ip = err_pos;
7865                 UNVERIFIED;
7866         }
7867
7868         if (cfg->method == method)
7869                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
7870
7871         for (n = 0; n < header->num_locals; ++n) {
7872                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7873                         UNVERIFIED;
7874         }
7875         class_inits = NULL;
7876
7877         /* We force the vtable variable here for all shared methods
7878            for the possibility that they might show up in a stack
7879            trace where their exact instantiation is needed. */
7880         if (cfg->gshared && method == cfg->method) {
7881                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7882                                 mini_method_get_context (method)->method_inst ||
7883                                 method->klass->valuetype) {
7884                         mono_get_vtable_var (cfg);
7885                 } else {
7886                         /* FIXME: Is there a better way to do this?
7887                            We need the variable live for the duration
7888                            of the whole method. */
7889                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7890                 }
7891         }
7892
7893         /* add a check for this != NULL to inlined methods */
7894         if (is_virtual_call) {
7895                 MonoInst *arg_ins;
7896
7897                 NEW_ARGLOAD (cfg, arg_ins, 0);
7898                 MONO_ADD_INS (cfg->cbb, arg_ins);
7899                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7900         }
7901
7902         skip_dead_blocks = !dont_verify;
7903         if (skip_dead_blocks) {
7904                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
7905                 CHECK_CFG_ERROR;
7906                 g_assert (bb);
7907         }
7908
7909         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7910         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7911
7912         ins_flag = 0;
7913         start_new_bblock = 0;
7914         while (ip < end) {
7915                 if (cfg->method == method)
7916                         cfg->real_offset = ip - header->code;
7917                 else
7918                         cfg->real_offset = inline_offset;
7919                 cfg->ip = ip;
7920
7921                 context_used = 0;
7922
7923                 if (start_new_bblock) {
7924                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
7925                         if (start_new_bblock == 2) {
7926                                 g_assert (ip == tblock->cil_code);
7927                         } else {
7928                                 GET_BBLOCK (cfg, tblock, ip);
7929                         }
7930                         cfg->cbb->next_bb = tblock;
7931                         cfg->cbb = tblock;
7932                         start_new_bblock = 0;
7933                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
7934                                 if (cfg->verbose_level > 3)
7935                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7936                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7937                                 *sp++ = ins;
7938                         }
7939                         if (class_inits)
7940                                 g_slist_free (class_inits);
7941                         class_inits = NULL;
7942                 } else {
7943                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
7944                                 link_bblock (cfg, cfg->cbb, tblock);
7945                                 if (sp != stack_start) {
7946                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7947                                         sp = stack_start;
7948                                         CHECK_UNVERIFIABLE (cfg);
7949                                 }
7950                                 cfg->cbb->next_bb = tblock;
7951                                 cfg->cbb = tblock;
7952                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
7953                                         if (cfg->verbose_level > 3)
7954                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7955                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7956                                         *sp++ = ins;
7957                                 }
7958                                 g_slist_free (class_inits);
7959                                 class_inits = NULL;
7960                         }
7961                 }
7962
7963                 if (skip_dead_blocks) {
7964                         int ip_offset = ip - header->code;
7965
7966                         if (ip_offset == bb->end)
7967                                 bb = bb->next;
7968
7969                         if (bb->dead) {
7970                                 int op_size = mono_opcode_size (ip, end);
7971                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7972
7973                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7974
7975                                 if (ip_offset + op_size == bb->end) {
7976                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7977                                         MONO_ADD_INS (cfg->cbb, ins);
7978                                         start_new_bblock = 1;
7979                                 }
7980
7981                                 ip += op_size;
7982                                 continue;
7983                         }
7984                 }
7985                 /*
7986                  * Sequence points are points where the debugger can place a breakpoint.
7987                  * Currently, we generate these automatically at points where the IL
7988                  * stack is empty.
7989                  */
7990                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7991                         /*
7992                          * Make methods interruptable at the beginning, and at the targets of
7993                          * backward branches.
7994                          * Also, do this at the start of every bblock in methods with clauses too,
7995                          * to be able to handle instructions with inprecise control flow like
7996                          * throw/endfinally.
7997                          * Backward branches are handled at the end of method-to-ir ().
7998                          */
7999                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8000                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8001
8002                         /* Avoid sequence points on empty IL like .volatile */
8003                         // FIXME: Enable this
8004                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8005                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8006                         if ((sp != stack_start) && !sym_seq_point)
8007                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8008                         MONO_ADD_INS (cfg->cbb, ins);
8009
8010                         if (sym_seq_points)
8011                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8012                 }
8013
8014                 cfg->cbb->real_offset = cfg->real_offset;
8015
8016                 if ((cfg->method == method) && cfg->coverage_info) {
8017                         guint32 cil_offset = ip - header->code;
8018                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8019
8020                         /* TODO: Use an increment here */
8021 #if defined(TARGET_X86)
8022                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8023                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8024                         ins->inst_imm = 1;
8025                         MONO_ADD_INS (cfg->cbb, ins);
8026 #else
8027                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8028                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8029 #endif
8030                 }
8031
8032                 if (cfg->verbose_level > 3)
8033                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8034
8035                 switch (*ip) {
8036                 case CEE_NOP:
8037                         if (seq_points && !sym_seq_points && sp != stack_start) {
8038                                 /*
8039                                  * The C# compiler uses these nops to notify the JIT that it should
8040                                  * insert seq points.
8041                                  */
8042                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8043                                 MONO_ADD_INS (cfg->cbb, ins);
8044                         }
8045                         if (cfg->keep_cil_nops)
8046                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8047                         else
8048                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8049                         ip++;
8050                         MONO_ADD_INS (cfg->cbb, ins);
8051                         break;
8052                 case CEE_BREAK:
8053                         if (should_insert_brekpoint (cfg->method)) {
8054                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8055                         } else {
8056                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8057                         }
8058                         ip++;
8059                         MONO_ADD_INS (cfg->cbb, ins);
8060                         break;
8061                 case CEE_LDARG_0:
8062                 case CEE_LDARG_1:
8063                 case CEE_LDARG_2:
8064                 case CEE_LDARG_3:
8065                         CHECK_STACK_OVF (1);
8066                         n = (*ip)-CEE_LDARG_0;
8067                         CHECK_ARG (n);
8068                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8069                         ip++;
8070                         *sp++ = ins;
8071                         break;
8072                 case CEE_LDLOC_0:
8073                 case CEE_LDLOC_1:
8074                 case CEE_LDLOC_2:
8075                 case CEE_LDLOC_3:
8076                         CHECK_STACK_OVF (1);
8077                         n = (*ip)-CEE_LDLOC_0;
8078                         CHECK_LOCAL (n);
8079                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8080                         ip++;
8081                         *sp++ = ins;
8082                         break;
8083                 case CEE_STLOC_0:
8084                 case CEE_STLOC_1:
8085                 case CEE_STLOC_2:
8086                 case CEE_STLOC_3: {
8087                         CHECK_STACK (1);
8088                         n = (*ip)-CEE_STLOC_0;
8089                         CHECK_LOCAL (n);
8090                         --sp;
8091                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8092                                 UNVERIFIED;
8093                         emit_stloc_ir (cfg, sp, header, n);
8094                         ++ip;
8095                         inline_costs += 1;
8096                         break;
8097                         }
8098                 case CEE_LDARG_S:
8099                         CHECK_OPSIZE (2);
8100                         CHECK_STACK_OVF (1);
8101                         n = ip [1];
8102                         CHECK_ARG (n);
8103                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8104                         *sp++ = ins;
8105                         ip += 2;
8106                         break;
8107                 case CEE_LDARGA_S:
8108                         CHECK_OPSIZE (2);
8109                         CHECK_STACK_OVF (1);
8110                         n = ip [1];
8111                         CHECK_ARG (n);
8112                         NEW_ARGLOADA (cfg, ins, n);
8113                         MONO_ADD_INS (cfg->cbb, ins);
8114                         *sp++ = ins;
8115                         ip += 2;
8116                         break;
8117                 case CEE_STARG_S:
8118                         CHECK_OPSIZE (2);
8119                         CHECK_STACK (1);
8120                         --sp;
8121                         n = ip [1];
8122                         CHECK_ARG (n);
8123                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8124                                 UNVERIFIED;
8125                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8126                         ip += 2;
8127                         break;
8128                 case CEE_LDLOC_S:
8129                         CHECK_OPSIZE (2);
8130                         CHECK_STACK_OVF (1);
8131                         n = ip [1];
8132                         CHECK_LOCAL (n);
8133                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8134                         *sp++ = ins;
8135                         ip += 2;
8136                         break;
8137                 case CEE_LDLOCA_S: {
8138                         unsigned char *tmp_ip;
8139                         CHECK_OPSIZE (2);
8140                         CHECK_STACK_OVF (1);
8141                         CHECK_LOCAL (ip [1]);
8142
8143                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8144                                 ip = tmp_ip;
8145                                 inline_costs += 1;
8146                                 break;
8147                         }
8148
8149                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8150                         *sp++ = ins;
8151                         ip += 2;
8152                         break;
8153                 }
8154                 case CEE_STLOC_S:
8155                         CHECK_OPSIZE (2);
8156                         CHECK_STACK (1);
8157                         --sp;
8158                         CHECK_LOCAL (ip [1]);
8159                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8160                                 UNVERIFIED;
8161                         emit_stloc_ir (cfg, sp, header, ip [1]);
8162                         ip += 2;
8163                         inline_costs += 1;
8164                         break;
8165                 case CEE_LDNULL:
8166                         CHECK_STACK_OVF (1);
8167                         EMIT_NEW_PCONST (cfg, ins, NULL);
8168                         ins->type = STACK_OBJ;
8169                         ++ip;
8170                         *sp++ = ins;
8171                         break;
8172                 case CEE_LDC_I4_M1:
8173                         CHECK_STACK_OVF (1);
8174                         EMIT_NEW_ICONST (cfg, ins, -1);
8175                         ++ip;
8176                         *sp++ = ins;
8177                         break;
8178                 case CEE_LDC_I4_0:
8179                 case CEE_LDC_I4_1:
8180                 case CEE_LDC_I4_2:
8181                 case CEE_LDC_I4_3:
8182                 case CEE_LDC_I4_4:
8183                 case CEE_LDC_I4_5:
8184                 case CEE_LDC_I4_6:
8185                 case CEE_LDC_I4_7:
8186                 case CEE_LDC_I4_8:
8187                         CHECK_STACK_OVF (1);
8188                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8189                         ++ip;
8190                         *sp++ = ins;
8191                         break;
8192                 case CEE_LDC_I4_S:
8193                         CHECK_OPSIZE (2);
8194                         CHECK_STACK_OVF (1);
8195                         ++ip;
8196                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8197                         ++ip;
8198                         *sp++ = ins;
8199                         break;
8200                 case CEE_LDC_I4:
8201                         CHECK_OPSIZE (5);
8202                         CHECK_STACK_OVF (1);
8203                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8204                         ip += 5;
8205                         *sp++ = ins;
8206                         break;
8207                 case CEE_LDC_I8:
8208                         CHECK_OPSIZE (9);
8209                         CHECK_STACK_OVF (1);
8210                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8211                         ins->type = STACK_I8;
8212                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8213                         ++ip;
8214                         ins->inst_l = (gint64)read64 (ip);
8215                         MONO_ADD_INS (cfg->cbb, ins);
8216                         ip += 8;
8217                         *sp++ = ins;
8218                         break;
8219                 case CEE_LDC_R4: {
8220                         float *f;
8221                         gboolean use_aotconst = FALSE;
8222
8223 #ifdef TARGET_POWERPC
8224                         /* FIXME: Clean this up */
8225                         if (cfg->compile_aot)
8226                                 use_aotconst = TRUE;
8227 #endif
8228
8229                         /* FIXME: we should really allocate this only late in the compilation process */
8230                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8231                         CHECK_OPSIZE (5);
8232                         CHECK_STACK_OVF (1);
8233
8234                         if (use_aotconst) {
8235                                 MonoInst *cons;
8236                                 int dreg;
8237
8238                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8239
8240                                 dreg = alloc_freg (cfg);
8241                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8242                                 ins->type = cfg->r4_stack_type;
8243                         } else {
8244                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8245                                 ins->type = cfg->r4_stack_type;
8246                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8247                                 ins->inst_p0 = f;
8248                                 MONO_ADD_INS (cfg->cbb, ins);
8249                         }
8250                         ++ip;
8251                         readr4 (ip, f);
8252                         ip += 4;
8253                         *sp++ = ins;                    
8254                         break;
8255                 }
8256                 case CEE_LDC_R8: {
8257                         double *d;
8258                         gboolean use_aotconst = FALSE;
8259
8260 #ifdef TARGET_POWERPC
8261                         /* FIXME: Clean this up */
8262                         if (cfg->compile_aot)
8263                                 use_aotconst = TRUE;
8264 #endif
8265
8266                         /* FIXME: we should really allocate this only late in the compilation process */
8267                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8268                         CHECK_OPSIZE (9);
8269                         CHECK_STACK_OVF (1);
8270
8271                         if (use_aotconst) {
8272                                 MonoInst *cons;
8273                                 int dreg;
8274
8275                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8276
8277                                 dreg = alloc_freg (cfg);
8278                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8279                                 ins->type = STACK_R8;
8280                         } else {
8281                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8282                                 ins->type = STACK_R8;
8283                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8284                                 ins->inst_p0 = d;
8285                                 MONO_ADD_INS (cfg->cbb, ins);
8286                         }
8287                         ++ip;
8288                         readr8 (ip, d);
8289                         ip += 8;
8290                         *sp++ = ins;
8291                         break;
8292                 }
8293                 case CEE_DUP: {
8294                         MonoInst *temp, *store;
8295                         CHECK_STACK (1);
8296                         CHECK_STACK_OVF (1);
8297                         sp--;
8298                         ins = *sp;
8299
8300                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8301                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8302
8303                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8304                         *sp++ = ins;
8305
8306                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8307                         *sp++ = ins;
8308
8309                         ++ip;
8310                         inline_costs += 2;
8311                         break;
8312                 }
8313                 case CEE_POP:
8314                         CHECK_STACK (1);
8315                         ip++;
8316                         --sp;
8317
8318 #ifdef TARGET_X86
8319                         if (sp [0]->type == STACK_R8)
8320                                 /* we need to pop the value from the x86 FP stack */
8321                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8322 #endif
8323                         break;
8324                 case CEE_JMP: {
8325                         MonoCallInst *call;
8326                         MonoMethodSignature *fsig;
8327                         int i, n;
8328
8329                         INLINE_FAILURE ("jmp");
8330                         GSHAREDVT_FAILURE (*ip);
8331
8332                         CHECK_OPSIZE (5);
8333                         if (stack_start != sp)
8334                                 UNVERIFIED;
8335                         token = read32 (ip + 1);
8336                         /* FIXME: check the signature matches */
8337                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8338                         CHECK_CFG_ERROR;
8339  
8340                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8341                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8342
8343                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8344
8345                         fsig = mono_method_signature (cmethod);
8346                         n = fsig->param_count + fsig->hasthis;
8347                         if (cfg->llvm_only) {
8348                                 MonoInst **args;
8349
8350                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8351                                 for (i = 0; i < n; ++i)
8352                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8353                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8354                                 /*
8355                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8356                                  * have to emit a normal return since llvm expects it.
8357                                  */
8358                                 if (cfg->ret)
8359                                         emit_setret (cfg, ins);
8360                                 MONO_INST_NEW (cfg, ins, OP_BR);
8361                                 ins->inst_target_bb = end_bblock;
8362                                 MONO_ADD_INS (cfg->cbb, ins);
8363                                 link_bblock (cfg, cfg->cbb, end_bblock);
8364                                 ip += 5;
8365                                 break;
8366                         } else if (cfg->backend->have_op_tail_call) {
8367                                 /* Handle tail calls similarly to calls */
8368                                 DISABLE_AOT (cfg);
8369
8370                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8371                                 call->method = cmethod;
8372                                 call->tail_call = TRUE;
8373                                 call->signature = mono_method_signature (cmethod);
8374                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8375                                 call->inst.inst_p0 = cmethod;
8376                                 for (i = 0; i < n; ++i)
8377                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8378
8379                                 if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
8380                                         call->vret_var = cfg->vret_addr;
8381
8382                                 mono_arch_emit_call (cfg, call);
8383                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8384                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8385                         } else {
8386                                 for (i = 0; i < num_args; ++i)
8387                                         /* Prevent arguments from being optimized away */
8388                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8389
8390                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8391                                 ins = (MonoInst*)call;
8392                                 ins->inst_p0 = cmethod;
8393                                 MONO_ADD_INS (cfg->cbb, ins);
8394                         }
8395
8396                         ip += 5;
8397                         start_new_bblock = 1;
8398                         break;
8399                 }
8400                 case CEE_CALLI: {
8401                         MonoInst *addr;
8402                         MonoMethodSignature *fsig;
8403
8404                         CHECK_OPSIZE (5);
8405                         token = read32 (ip + 1);
8406
8407                         ins = NULL;
8408
8409                         //GSHAREDVT_FAILURE (*ip);
8410                         cmethod = NULL;
8411                         CHECK_STACK (1);
8412                         --sp;
8413                         addr = *sp;
8414                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
8415                         CHECK_CFG_ERROR;
8416
8417                         if (method->dynamic && fsig->pinvoke) {
8418                                 MonoInst *args [3];
8419
8420                                 /*
8421                                  * This is a call through a function pointer using a pinvoke
8422                                  * signature. Have to create a wrapper and call that instead.
8423                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8424                                  * instead based on the signature.
8425                                  */
8426                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8427                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8428                                 args [2] = addr;
8429                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8430                         }
8431
8432                         n = fsig->param_count + fsig->hasthis;
8433
8434                         CHECK_STACK (n);
8435
8436                         //g_assert (!virtual_ || fsig->hasthis);
8437
8438                         sp -= n;
8439
8440                         inline_costs += 10 * num_calls++;
8441
8442                         /*
8443                          * Making generic calls out of gsharedvt methods.
8444                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8445                          * patching gshared method addresses into a gsharedvt method.
8446                          */
8447                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8448                                 /*
8449                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8450                                  */
8451                                 MonoInst *callee = addr;
8452
8453                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8454                                         /* Not tested */
8455                                         GSHAREDVT_FAILURE (*ip);
8456
8457                                 if (cfg->llvm_only)
8458                                         // FIXME:
8459                                         GSHAREDVT_FAILURE (*ip);
8460
8461                                 addr = emit_get_rgctx_sig (cfg, context_used,
8462                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8463                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8464                                 goto calli_end;
8465                         }
8466
8467                         /* Prevent inlining of methods with indirect calls */
8468                         INLINE_FAILURE ("indirect call");
8469
8470                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8471                                 MonoJumpInfoType info_type;
8472                                 gpointer info_data;
8473
8474                                 /*
8475                                  * Instead of emitting an indirect call, emit a direct call
8476                                  * with the contents of the aotconst as the patch info.
8477                                  */
8478                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8479                                         info_type = (MonoJumpInfoType)addr->inst_c1;
8480                                         info_data = addr->inst_p0;
8481                                 } else {
8482                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
8483                                         info_data = addr->inst_right->inst_left;
8484                                 }
8485
8486                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
8487                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
8488                                         NULLIFY_INS (addr);
8489                                         goto calli_end;
8490                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8491                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8492                                         NULLIFY_INS (addr);
8493                                         goto calli_end;
8494                                 }
8495                         }
8496                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8497
8498                         calli_end:
8499
8500                         /* End of call, INS should contain the result of the call, if any */
8501
8502                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8503                                 g_assert (ins);
8504                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8505                         }
8506
8507                         CHECK_CFG_EXCEPTION;
8508
8509                         ip += 5;
8510                         ins_flag = 0;
8511                         constrained_class = NULL;
8512                         break;
8513                 }
8514                 case CEE_CALL:
8515                 case CEE_CALLVIRT: {
8516                         MonoInst *addr = NULL;
8517                         MonoMethodSignature *fsig = NULL;
8518                         int array_rank = 0;
8519                         int virtual_ = *ip == CEE_CALLVIRT;
8520                         gboolean pass_imt_from_rgctx = FALSE;
8521                         MonoInst *imt_arg = NULL;
8522                         MonoInst *keep_this_alive = NULL;
8523                         gboolean pass_vtable = FALSE;
8524                         gboolean pass_mrgctx = FALSE;
8525                         MonoInst *vtable_arg = NULL;
8526                         gboolean check_this = FALSE;
8527                         gboolean supported_tail_call = FALSE;
8528                         gboolean tail_call = FALSE;
8529                         gboolean need_seq_point = FALSE;
8530                         guint32 call_opcode = *ip;
8531                         gboolean emit_widen = TRUE;
8532                         gboolean push_res = TRUE;
8533                         gboolean skip_ret = FALSE;
8534                         gboolean delegate_invoke = FALSE;
8535                         gboolean direct_icall = FALSE;
8536                         gboolean constrained_partial_call = FALSE;
8537                         MonoMethod *cil_method;
8538
8539                         CHECK_OPSIZE (5);
8540                         token = read32 (ip + 1);
8541
8542                         ins = NULL;
8543
8544                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8545                         CHECK_CFG_ERROR;
8546
8547                         cil_method = cmethod;
8548                                 
8549                         if (constrained_class) {
8550                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8551                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8552                                                 g_assert (!cmethod->klass->valuetype);
8553                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8554                                                         constrained_partial_call = TRUE;
8555                                         }
8556                                 }
8557
8558                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8559                                         if (cfg->verbose_level > 2)
8560                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8561                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8562                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8563                                                   cfg->gshared)) {
8564                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8565                                                 CHECK_CFG_ERROR;
8566                                         }
8567                                 } else {
8568                                         if (cfg->verbose_level > 2)
8569                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8570
8571                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8572                                                 /* 
8573                                                  * This is needed since get_method_constrained can't find 
8574                                                  * the method in klass representing a type var.
8575                                                  * The type var is guaranteed to be a reference type in this
8576                                                  * case.
8577                                                  */
8578                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8579                                                         g_assert (!cmethod->klass->valuetype);
8580                                         } else {
8581                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8582                                                 CHECK_CFG_ERROR;
8583                                         }
8584                                 }
8585                         }
8586                                         
8587                         if (!dont_verify && !cfg->skip_visibility) {
8588                                 MonoMethod *target_method = cil_method;
8589                                 if (method->is_inflated) {
8590                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
8591                                         CHECK_CFG_ERROR;
8592                                 }
8593                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8594                                         !mono_method_can_access_method (method, cil_method))
8595                                         emit_method_access_failure (cfg, method, cil_method);
8596                         }
8597
8598                         if (mono_security_core_clr_enabled ())
8599                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8600
8601                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8602                                 /* MS.NET seems to silently convert this to a callvirt */
8603                                 virtual_ = 1;
8604
8605                         {
8606                                 /*
8607                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8608                                  * converts to a callvirt.
8609                                  *
8610                                  * tests/bug-515884.il is an example of this behavior
8611                                  */
8612                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8613                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8614                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8615                                         virtual_ = 1;
8616                         }
8617
8618                         if (!cmethod->klass->inited)
8619                                 if (!mono_class_init (cmethod->klass))
8620                                         TYPE_LOAD_ERROR (cmethod->klass);
8621
8622                         fsig = mono_method_signature (cmethod);
8623                         if (!fsig)
8624                                 LOAD_ERROR;
8625                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8626                                 mini_class_is_system_array (cmethod->klass)) {
8627                                 array_rank = cmethod->klass->rank;
8628                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8629                                 direct_icall = TRUE;
8630                         } else if (fsig->pinvoke) {
8631                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8632                                 fsig = mono_method_signature (wrapper);
8633                         } else if (constrained_class) {
8634                         } else {
8635                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8636                                 CHECK_CFG_ERROR;
8637                         }
8638
8639                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
8640                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
8641
8642                         /* See code below */
8643                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8644                                 MonoBasicBlock *tbb;
8645
8646                                 GET_BBLOCK (cfg, tbb, ip + 5);
8647                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8648                                         /*
8649                                          * We want to extend the try block to cover the call, but we can't do it if the
8650                                          * call is made directly since its followed by an exception check.
8651                                          */
8652                                         direct_icall = FALSE;
8653                                 }
8654                         }
8655
8656                         mono_save_token_info (cfg, image, token, cil_method);
8657
8658                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8659                                 need_seq_point = TRUE;
8660
8661                         /* Don't support calls made using type arguments for now */
8662                         /*
8663                           if (cfg->gsharedvt) {
8664                           if (mini_is_gsharedvt_signature (fsig))
8665                           GSHAREDVT_FAILURE (*ip);
8666                           }
8667                         */
8668
8669                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8670                                 g_assert_not_reached ();
8671
8672                         n = fsig->param_count + fsig->hasthis;
8673
8674                         if (!cfg->gshared && mono_class_is_gtd (cmethod->klass))
8675                                 UNVERIFIED;
8676
8677                         if (!cfg->gshared)
8678                                 g_assert (!mono_method_check_context_used (cmethod));
8679
8680                         CHECK_STACK (n);
8681
8682                         //g_assert (!virtual_ || fsig->hasthis);
8683
8684                         sp -= n;
8685
8686                         /*
8687                          * We have the `constrained.' prefix opcode.
8688                          */
8689                         if (constrained_class) {
8690                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8691                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8692                                                 /* The 'Own method' case below */
8693                                         } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) {
8694                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8695                                         } else {
8696                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8697                                                 CHECK_CFG_EXCEPTION;
8698                                                 g_assert (ins);
8699                                                 goto call_end;
8700                                         }
8701                                 }
8702
8703                                 if (constrained_partial_call) {
8704                                         gboolean need_box = TRUE;
8705
8706                                         /*
8707                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8708                                          * called method is not known at compile time either. The called method could end up being
8709                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8710                                          * to box the receiver.
8711                                          * A simple solution would be to box always and make a normal virtual call, but that would
8712                                          * be bad performance wise.
8713                                          */
8714                                         if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) {
8715                                                 /*
8716                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8717                                                  */
8718                                                 need_box = FALSE;
8719                                         }
8720
8721                                         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)) {
8722                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8723                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8724                                                 ins->klass = constrained_class;
8725                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8726                                                 CHECK_CFG_EXCEPTION;
8727                                         } else if (need_box) {
8728                                                 MonoInst *box_type;
8729                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8730                                                 MonoInst *nonbox_call;
8731
8732                                                 /*
8733                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8734                                                  * if needed.
8735                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8736                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8737                                                  */
8738                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8739
8740                                                 NEW_BBLOCK (cfg, is_ref_bb);
8741                                                 NEW_BBLOCK (cfg, end_bb);
8742
8743                                                 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);
8744                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
8745                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
8746
8747                                                 /* Non-ref case */
8748                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8749
8750                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8751
8752                                                 /* Ref case */
8753                                                 MONO_START_BB (cfg, is_ref_bb);
8754                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8755                                                 ins->klass = constrained_class;
8756                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8757                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8758
8759                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8760
8761                                                 MONO_START_BB (cfg, end_bb);
8762                                                 cfg->cbb = end_bb;
8763
8764                                                 nonbox_call->dreg = ins->dreg;
8765                                                 goto call_end;
8766                                         } else {
8767                                                 g_assert (mono_class_is_interface (cmethod->klass));
8768                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8769                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8770                                                 goto call_end;
8771                                         }
8772                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8773                                         /*
8774                                          * The type parameter is instantiated as a valuetype,
8775                                          * but that type doesn't override the method we're
8776                                          * calling, so we need to box `this'.
8777                                          */
8778                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8779                                         ins->klass = constrained_class;
8780                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8781                                         CHECK_CFG_EXCEPTION;
8782                                 } else if (!constrained_class->valuetype) {
8783                                         int dreg = alloc_ireg_ref (cfg);
8784
8785                                         /*
8786                                          * The type parameter is instantiated as a reference
8787                                          * type.  We have a managed pointer on the stack, so
8788                                          * we need to dereference it here.
8789                                          */
8790                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8791                                         ins->type = STACK_OBJ;
8792                                         sp [0] = ins;
8793                                 } else {
8794                                         if (cmethod->klass->valuetype) {
8795                                                 /* Own method */
8796                                         } else {
8797                                                 /* Interface method */
8798                                                 int ioffset, slot;
8799
8800                                                 mono_class_setup_vtable (constrained_class);
8801                                                 CHECK_TYPELOAD (constrained_class);
8802                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8803                                                 if (ioffset == -1)
8804                                                         TYPE_LOAD_ERROR (constrained_class);
8805                                                 slot = mono_method_get_vtable_slot (cmethod);
8806                                                 if (slot == -1)
8807                                                         TYPE_LOAD_ERROR (cmethod->klass);
8808                                                 cmethod = constrained_class->vtable [ioffset + slot];
8809
8810                                                 if (cmethod->klass == mono_defaults.enum_class) {
8811                                                         /* Enum implements some interfaces, so treat this as the first case */
8812                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8813                                                         ins->klass = constrained_class;
8814                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8815                                                         CHECK_CFG_EXCEPTION;
8816                                                 }
8817                                         }
8818                                         virtual_ = 0;
8819                                 }
8820                                 constrained_class = NULL;
8821                         }
8822
8823                         if (check_call_signature (cfg, fsig, sp))
8824                                 UNVERIFIED;
8825
8826                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8827                                 delegate_invoke = TRUE;
8828
8829                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8830                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8831                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8832                                         emit_widen = FALSE;
8833                                 }
8834
8835                                 goto call_end;
8836                         }
8837
8838                         /* 
8839                          * If the callee is a shared method, then its static cctor
8840                          * might not get called after the call was patched.
8841                          */
8842                         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)) {
8843                                 emit_class_init (cfg, cmethod->klass);
8844                                 CHECK_TYPELOAD (cmethod->klass);
8845                         }
8846
8847                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8848
8849                         if (cfg->gshared) {
8850                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8851
8852                                 context_used = mini_method_check_context_used (cfg, cmethod);
8853
8854                                 if (context_used && mono_class_is_interface (cmethod->klass)) {
8855                                         /* Generic method interface
8856                                            calls are resolved via a
8857                                            helper function and don't
8858                                            need an imt. */
8859                                         if (!cmethod_context || !cmethod_context->method_inst)
8860                                                 pass_imt_from_rgctx = TRUE;
8861                                 }
8862
8863                                 /*
8864                                  * If a shared method calls another
8865                                  * shared method then the caller must
8866                                  * have a generic sharing context
8867                                  * because the magic trampoline
8868                                  * requires it.  FIXME: We shouldn't
8869                                  * have to force the vtable/mrgctx
8870                                  * variable here.  Instead there
8871                                  * should be a flag in the cfg to
8872                                  * request a generic sharing context.
8873                                  */
8874                                 if (context_used &&
8875                                                 ((cfg->method->flags & METHOD_ATTRIBUTE_STATIC) || cfg->method->klass->valuetype))
8876                                         mono_get_vtable_var (cfg);
8877                         }
8878
8879                         if (pass_vtable) {
8880                                 if (context_used) {
8881                                         vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8882                                 } else {
8883                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8884
8885                                         CHECK_TYPELOAD (cmethod->klass);
8886                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8887                                 }
8888                         }
8889
8890                         if (pass_mrgctx) {
8891                                 g_assert (!vtable_arg);
8892
8893                                 if (!cfg->compile_aot) {
8894                                         /* 
8895                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8896                                          * for type load errors before.
8897                                          */
8898                                         mono_class_setup_vtable (cmethod->klass);
8899                                         CHECK_TYPELOAD (cmethod->klass);
8900                                 }
8901
8902                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8903
8904                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8905                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8906                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8907                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8908                                         if (virtual_)
8909                                                 check_this = TRUE;
8910                                         virtual_ = 0;
8911                                 }
8912                         }
8913
8914                         if (pass_imt_from_rgctx) {
8915                                 g_assert (!pass_vtable);
8916
8917                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8918                                         cmethod, MONO_RGCTX_INFO_METHOD);
8919                         }
8920
8921                         if (check_this)
8922                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8923
8924                         /* Calling virtual generic methods */
8925                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
8926                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8927                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8928                             fsig->generic_param_count && 
8929                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
8930                                 !cfg->llvm_only) {
8931                                 MonoInst *this_temp, *this_arg_temp, *store;
8932                                 MonoInst *iargs [4];
8933
8934                                 g_assert (fsig->is_inflated);
8935
8936                                 /* Prevent inlining of methods that contain indirect calls */
8937                                 INLINE_FAILURE ("virtual generic call");
8938
8939                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8940                                         GSHAREDVT_FAILURE (*ip);
8941
8942                                 if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
8943                                         g_assert (!imt_arg);
8944                                         if (!context_used)
8945                                                 g_assert (cmethod->is_inflated);
8946                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8947                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8948                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8949                                 } else {
8950                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8951                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8952                                         MONO_ADD_INS (cfg->cbb, store);
8953
8954                                         /* FIXME: This should be a managed pointer */
8955                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8956
8957                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8958                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8959                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8960                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8961                                         addr = mono_emit_jit_icall (cfg,
8962                                                                                                 mono_helper_compile_generic_method, iargs);
8963
8964                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8965
8966                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8967                                 }
8968
8969                                 goto call_end;
8970                         }
8971
8972                         /*
8973                          * Implement a workaround for the inherent races involved in locking:
8974                          * Monitor.Enter ()
8975                          * try {
8976                          * } finally {
8977                          *    Monitor.Exit ()
8978                          * }
8979                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8980                          * try block, the Exit () won't be executed, see:
8981                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8982                          * To work around this, we extend such try blocks to include the last x bytes
8983                          * of the Monitor.Enter () call.
8984                          */
8985                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8986                                 MonoBasicBlock *tbb;
8987
8988                                 GET_BBLOCK (cfg, tbb, ip + 5);
8989                                 /* 
8990                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
8991                                  * from Monitor.Enter like ArgumentNullException.
8992                                  */
8993                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8994                                         /* Mark this bblock as needing to be extended */
8995                                         tbb->extend_try_block = TRUE;
8996                                 }
8997                         }
8998
8999                         /* Conversion to a JIT intrinsic */
9000                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9001                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9002                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9003                                         emit_widen = FALSE;
9004                                 }
9005                                 goto call_end;
9006                         }
9007                         CHECK_CFG_ERROR;
9008                         
9009                         /* Inlining */
9010                         if ((cfg->opt & MONO_OPT_INLINE) &&
9011                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9012                             mono_method_check_inlining (cfg, cmethod)) {
9013                                 int costs;
9014                                 gboolean always = FALSE;
9015
9016                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9017                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9018                                         /* Prevent inlining of methods that call wrappers */
9019                                         INLINE_FAILURE ("wrapper call");
9020                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9021                                         always = TRUE;
9022                                 }
9023
9024                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9025                                 if (costs) {
9026                                         cfg->real_offset += 5;
9027
9028                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9029                                                 /* *sp is already set by inline_method */
9030                                                 sp++;
9031                                                 push_res = FALSE;
9032                                         }
9033
9034                                         inline_costs += costs;
9035
9036                                         goto call_end;
9037                                 }
9038                         }
9039
9040                         /* Tail recursion elimination */
9041                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9042                                 gboolean has_vtargs = FALSE;
9043                                 int i;
9044
9045                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9046                                 INLINE_FAILURE ("tail call");
9047
9048                                 /* keep it simple */
9049                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9050                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9051                                                 has_vtargs = TRUE;
9052                                 }
9053
9054                                 if (!has_vtargs) {
9055                                         if (need_seq_point) {
9056                                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9057                                                 need_seq_point = FALSE;
9058                                         }
9059                                         for (i = 0; i < n; ++i)
9060                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9061                                         MONO_INST_NEW (cfg, ins, OP_BR);
9062                                         MONO_ADD_INS (cfg->cbb, ins);
9063                                         tblock = start_bblock->out_bb [0];
9064                                         link_bblock (cfg, cfg->cbb, tblock);
9065                                         ins->inst_target_bb = tblock;
9066                                         start_new_bblock = 1;
9067
9068                                         /* skip the CEE_RET, too */
9069                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9070                                                 skip_ret = TRUE;
9071                                         push_res = FALSE;
9072                                         goto call_end;
9073                                 }
9074                         }
9075
9076                         inline_costs += 10 * num_calls++;
9077
9078                         /*
9079                          * Synchronized wrappers.
9080                          * Its hard to determine where to replace a method with its synchronized
9081                          * wrapper without causing an infinite recursion. The current solution is
9082                          * to add the synchronized wrapper in the trampolines, and to
9083                          * change the called method to a dummy wrapper, and resolve that wrapper
9084                          * to the real method in mono_jit_compile_method ().
9085                          */
9086                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9087                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9088                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9089                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9090                         }
9091
9092                         /*
9093                          * Making generic calls out of gsharedvt methods.
9094                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9095                          * patching gshared method addresses into a gsharedvt method.
9096                          */
9097                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) &&
9098                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9099                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9100                                 MonoRgctxInfoType info_type;
9101
9102                                 if (virtual_) {
9103                                         //if (mono_class_is_interface (cmethod->klass))
9104                                                 //GSHAREDVT_FAILURE (*ip);
9105                                         // disable for possible remoting calls
9106                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9107                                                 GSHAREDVT_FAILURE (*ip);
9108                                         if (fsig->generic_param_count) {
9109                                                 /* virtual generic call */
9110                                                 g_assert (!imt_arg);
9111                                                 /* Same as the virtual generic case above */
9112                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9113                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9114                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9115                                                 vtable_arg = NULL;
9116                                         } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) {
9117                                                 /* This can happen when we call a fully instantiated iface method */
9118                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9119                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9120                                                 vtable_arg = NULL;
9121                                         }
9122                                 }
9123
9124                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9125                                         keep_this_alive = sp [0];
9126
9127                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9128                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9129                                 else
9130                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9131                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9132
9133                                 if (cfg->llvm_only) {
9134                                         // FIXME: Avoid initializing vtable_arg
9135                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9136                                 } else {
9137                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9138                                 }
9139                                 goto call_end;
9140                         }
9141
9142                         /* Generic sharing */
9143
9144                         /*
9145                          * Use this if the callee is gsharedvt sharable too, since
9146                          * at runtime we might find an instantiation so the call cannot
9147                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9148                          */
9149                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9150                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9151                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9152                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9153                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9154                                 INLINE_FAILURE ("gshared");
9155
9156                                 g_assert (cfg->gshared && cmethod);
9157                                 g_assert (!addr);
9158
9159                                 /*
9160                                  * We are compiling a call to a
9161                                  * generic method from shared code,
9162                                  * which means that we have to look up
9163                                  * the method in the rgctx and do an
9164                                  * indirect call.
9165                                  */
9166                                 if (fsig->hasthis)
9167                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9168
9169                                 if (cfg->llvm_only) {
9170                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9171                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9172                                         else
9173                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9174                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9175                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9176                                 } else {
9177                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9178                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9179                                 }
9180                                 goto call_end;
9181                         }
9182
9183                         /* Direct calls to icalls */
9184                         if (direct_icall) {
9185                                 MonoMethod *wrapper;
9186                                 int costs;
9187
9188                                 /* Inline the wrapper */
9189                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9190
9191                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9192                                 g_assert (costs > 0);
9193                                 cfg->real_offset += 5;
9194
9195                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9196                                         /* *sp is already set by inline_method */
9197                                         sp++;
9198                                         push_res = FALSE;
9199                                 }
9200
9201                                 inline_costs += costs;
9202
9203                                 goto call_end;
9204                         }
9205                                         
9206                         /* Array methods */
9207                         if (array_rank) {
9208                                 MonoInst *addr;
9209
9210                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9211                                         MonoInst *val = sp [fsig->param_count];
9212
9213                                         if (val->type == STACK_OBJ) {
9214                                                 MonoInst *iargs [2];
9215
9216                                                 iargs [0] = sp [0];
9217                                                 iargs [1] = val;
9218                                                 
9219                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9220                                         }
9221                                         
9222                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9223                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9224                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
9225                                                 emit_write_barrier (cfg, addr, val);
9226                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9227                                                 GSHAREDVT_FAILURE (*ip);
9228                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9229                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9230
9231                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9232                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9233                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9234                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9235                                         CHECK_TYPELOAD (cmethod->klass);
9236                                         
9237                                         readonly = FALSE;
9238                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9239                                         ins = addr;
9240                                 } else {
9241                                         g_assert_not_reached ();
9242                                 }
9243
9244                                 emit_widen = FALSE;
9245                                 goto call_end;
9246                         }
9247
9248                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9249                         if (ins)
9250                                 goto call_end;
9251
9252                         /* Tail prefix / tail call optimization */
9253
9254                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9255                         /* FIXME: runtime generic context pointer for jumps? */
9256                         /* FIXME: handle this for generic sharing eventually */
9257                         if ((ins_flag & MONO_INST_TAILCALL) &&
9258                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9259                                 supported_tail_call = TRUE;
9260
9261                         if (supported_tail_call) {
9262                                 MonoCallInst *call;
9263
9264                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9265                                 INLINE_FAILURE ("tail call");
9266
9267                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9268
9269                                 if (cfg->backend->have_op_tail_call) {
9270                                         /* Handle tail calls similarly to normal calls */
9271                                         tail_call = TRUE;
9272                                 } else {
9273                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9274
9275                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9276                                         call->tail_call = TRUE;
9277                                         call->method = cmethod;
9278                                         call->signature = mono_method_signature (cmethod);
9279
9280                                         /*
9281                                          * We implement tail calls by storing the actual arguments into the 
9282                                          * argument variables, then emitting a CEE_JMP.
9283                                          */
9284                                         for (i = 0; i < n; ++i) {
9285                                                 /* Prevent argument from being register allocated */
9286                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9287                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9288                                         }
9289                                         ins = (MonoInst*)call;
9290                                         ins->inst_p0 = cmethod;
9291                                         ins->inst_p1 = arg_array [0];
9292                                         MONO_ADD_INS (cfg->cbb, ins);
9293                                         link_bblock (cfg, cfg->cbb, end_bblock);
9294                                         start_new_bblock = 1;
9295
9296                                         // FIXME: Eliminate unreachable epilogs
9297
9298                                         /*
9299                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9300                                          * only reachable from this call.
9301                                          */
9302                                         GET_BBLOCK (cfg, tblock, ip + 5);
9303                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9304                                                 skip_ret = TRUE;
9305                                         push_res = FALSE;
9306
9307                                         goto call_end;
9308                                 }
9309                         }
9310
9311                         /*
9312                          * Virtual calls in llvm-only mode.
9313                          */
9314                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9315                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9316                                 goto call_end;
9317                         }
9318
9319                         /* Common call */
9320                         if (!(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
9321                                 INLINE_FAILURE ("call");
9322                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9323                                                                                           imt_arg, vtable_arg);
9324
9325                         if (tail_call && !cfg->llvm_only) {
9326                                 link_bblock (cfg, cfg->cbb, end_bblock);
9327                                 start_new_bblock = 1;
9328
9329                                 // FIXME: Eliminate unreachable epilogs
9330
9331                                 /*
9332                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9333                                  * only reachable from this call.
9334                                  */
9335                                 GET_BBLOCK (cfg, tblock, ip + 5);
9336                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9337                                         skip_ret = TRUE;
9338                                 push_res = FALSE;
9339                         }
9340
9341                         call_end:
9342
9343                         /* End of call, INS should contain the result of the call, if any */
9344
9345                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9346                                 g_assert (ins);
9347                                 if (emit_widen)
9348                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9349                                 else
9350                                         *sp++ = ins;
9351                         }
9352
9353                         if (keep_this_alive) {
9354                                 MonoInst *dummy_use;
9355
9356                                 /* See mono_emit_method_call_full () */
9357                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9358                         }
9359
9360                         if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
9361                                 /*
9362                                  * Clang can convert these calls to tail calls which screw up the stack
9363                                  * walk. This happens even when the -fno-optimize-sibling-calls
9364                                  * option is passed to clang.
9365                                  * Work around this by emitting a dummy call.
9366                                  */
9367                                 mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
9368                         }
9369
9370                         CHECK_CFG_EXCEPTION;
9371
9372                         ip += 5;
9373                         if (skip_ret) {
9374                                 g_assert (*ip == CEE_RET);
9375                                 ip += 1;
9376                         }
9377                         ins_flag = 0;
9378                         constrained_class = NULL;
9379                         if (need_seq_point)
9380                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9381                         break;
9382                 }
9383                 case CEE_RET:
9384                         if (cfg->method != method) {
9385                                 /* return from inlined method */
9386                                 /* 
9387                                  * If in_count == 0, that means the ret is unreachable due to
9388                                  * being preceeded by a throw. In that case, inline_method () will
9389                                  * handle setting the return value 
9390                                  * (test case: test_0_inline_throw ()).
9391                                  */
9392                                 if (return_var && cfg->cbb->in_count) {
9393                                         MonoType *ret_type = mono_method_signature (method)->ret;
9394
9395                                         MonoInst *store;
9396                                         CHECK_STACK (1);
9397                                         --sp;
9398
9399                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9400                                                 UNVERIFIED;
9401
9402                                         //g_assert (returnvar != -1);
9403                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9404                                         cfg->ret_var_set = TRUE;
9405                                 } 
9406                         } else {
9407                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9408
9409                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9410                                         emit_pop_lmf (cfg);
9411
9412                                 if (cfg->ret) {
9413                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9414
9415                                         if (seq_points && !sym_seq_points) {
9416                                                 /* 
9417                                                  * Place a seq point here too even through the IL stack is not
9418                                                  * empty, so a step over on
9419                                                  * call <FOO>
9420                                                  * ret
9421                                                  * will work correctly.
9422                                                  */
9423                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9424                                                 MONO_ADD_INS (cfg->cbb, ins);
9425                                         }
9426
9427                                         g_assert (!return_var);
9428                                         CHECK_STACK (1);
9429                                         --sp;
9430
9431                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9432                                                 UNVERIFIED;
9433
9434                                         emit_setret (cfg, *sp);
9435                                 }
9436                         }
9437                         if (sp != stack_start)
9438                                 UNVERIFIED;
9439                         MONO_INST_NEW (cfg, ins, OP_BR);
9440                         ip++;
9441                         ins->inst_target_bb = end_bblock;
9442                         MONO_ADD_INS (cfg->cbb, ins);
9443                         link_bblock (cfg, cfg->cbb, end_bblock);
9444                         start_new_bblock = 1;
9445                         break;
9446                 case CEE_BR_S:
9447                         CHECK_OPSIZE (2);
9448                         MONO_INST_NEW (cfg, ins, OP_BR);
9449                         ip++;
9450                         target = ip + 1 + (signed char)(*ip);
9451                         ++ip;
9452                         GET_BBLOCK (cfg, tblock, target);
9453                         link_bblock (cfg, cfg->cbb, tblock);
9454                         ins->inst_target_bb = tblock;
9455                         if (sp != stack_start) {
9456                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9457                                 sp = stack_start;
9458                                 CHECK_UNVERIFIABLE (cfg);
9459                         }
9460                         MONO_ADD_INS (cfg->cbb, ins);
9461                         start_new_bblock = 1;
9462                         inline_costs += BRANCH_COST;
9463                         break;
9464                 case CEE_BEQ_S:
9465                 case CEE_BGE_S:
9466                 case CEE_BGT_S:
9467                 case CEE_BLE_S:
9468                 case CEE_BLT_S:
9469                 case CEE_BNE_UN_S:
9470                 case CEE_BGE_UN_S:
9471                 case CEE_BGT_UN_S:
9472                 case CEE_BLE_UN_S:
9473                 case CEE_BLT_UN_S:
9474                         CHECK_OPSIZE (2);
9475                         CHECK_STACK (2);
9476                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9477                         ip++;
9478                         target = ip + 1 + *(signed char*)ip;
9479                         ip++;
9480
9481                         ADD_BINCOND (NULL);
9482
9483                         sp = stack_start;
9484                         inline_costs += BRANCH_COST;
9485                         break;
9486                 case CEE_BR:
9487                         CHECK_OPSIZE (5);
9488                         MONO_INST_NEW (cfg, ins, OP_BR);
9489                         ip++;
9490
9491                         target = ip + 4 + (gint32)read32(ip);
9492                         ip += 4;
9493                         GET_BBLOCK (cfg, tblock, target);
9494                         link_bblock (cfg, cfg->cbb, tblock);
9495                         ins->inst_target_bb = tblock;
9496                         if (sp != stack_start) {
9497                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9498                                 sp = stack_start;
9499                                 CHECK_UNVERIFIABLE (cfg);
9500                         }
9501
9502                         MONO_ADD_INS (cfg->cbb, ins);
9503
9504                         start_new_bblock = 1;
9505                         inline_costs += BRANCH_COST;
9506                         break;
9507                 case CEE_BRFALSE_S:
9508                 case CEE_BRTRUE_S:
9509                 case CEE_BRFALSE:
9510                 case CEE_BRTRUE: {
9511                         MonoInst *cmp;
9512                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9513                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9514                         guint32 opsize = is_short ? 1 : 4;
9515
9516                         CHECK_OPSIZE (opsize);
9517                         CHECK_STACK (1);
9518                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9519                                 UNVERIFIED;
9520                         ip ++;
9521                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9522                         ip += opsize;
9523
9524                         sp--;
9525
9526                         GET_BBLOCK (cfg, tblock, target);
9527                         link_bblock (cfg, cfg->cbb, tblock);
9528                         GET_BBLOCK (cfg, tblock, ip);
9529                         link_bblock (cfg, cfg->cbb, tblock);
9530
9531                         if (sp != stack_start) {
9532                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9533                                 CHECK_UNVERIFIABLE (cfg);
9534                         }
9535
9536                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9537                         cmp->sreg1 = sp [0]->dreg;
9538                         type_from_op (cfg, cmp, sp [0], NULL);
9539                         CHECK_TYPE (cmp);
9540
9541 #if SIZEOF_REGISTER == 4
9542                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9543                                 /* Convert it to OP_LCOMPARE */
9544                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9545                                 ins->type = STACK_I8;
9546                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9547                                 ins->inst_l = 0;
9548                                 MONO_ADD_INS (cfg->cbb, ins);
9549                                 cmp->opcode = OP_LCOMPARE;
9550                                 cmp->sreg2 = ins->dreg;
9551                         }
9552 #endif
9553                         MONO_ADD_INS (cfg->cbb, cmp);
9554
9555                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9556                         type_from_op (cfg, ins, sp [0], NULL);
9557                         MONO_ADD_INS (cfg->cbb, ins);
9558                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9559                         GET_BBLOCK (cfg, tblock, target);
9560                         ins->inst_true_bb = tblock;
9561                         GET_BBLOCK (cfg, tblock, ip);
9562                         ins->inst_false_bb = tblock;
9563                         start_new_bblock = 2;
9564
9565                         sp = stack_start;
9566                         inline_costs += BRANCH_COST;
9567                         break;
9568                 }
9569                 case CEE_BEQ:
9570                 case CEE_BGE:
9571                 case CEE_BGT:
9572                 case CEE_BLE:
9573                 case CEE_BLT:
9574                 case CEE_BNE_UN:
9575                 case CEE_BGE_UN:
9576                 case CEE_BGT_UN:
9577                 case CEE_BLE_UN:
9578                 case CEE_BLT_UN:
9579                         CHECK_OPSIZE (5);
9580                         CHECK_STACK (2);
9581                         MONO_INST_NEW (cfg, ins, *ip);
9582                         ip++;
9583                         target = ip + 4 + (gint32)read32(ip);
9584                         ip += 4;
9585
9586                         ADD_BINCOND (NULL);
9587
9588                         sp = stack_start;
9589                         inline_costs += BRANCH_COST;
9590                         break;
9591                 case CEE_SWITCH: {
9592                         MonoInst *src1;
9593                         MonoBasicBlock **targets;
9594                         MonoBasicBlock *default_bblock;
9595                         MonoJumpInfoBBTable *table;
9596                         int offset_reg = alloc_preg (cfg);
9597                         int target_reg = alloc_preg (cfg);
9598                         int table_reg = alloc_preg (cfg);
9599                         int sum_reg = alloc_preg (cfg);
9600                         gboolean use_op_switch;
9601
9602                         CHECK_OPSIZE (5);
9603                         CHECK_STACK (1);
9604                         n = read32 (ip + 1);
9605                         --sp;
9606                         src1 = sp [0];
9607                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9608                                 UNVERIFIED;
9609
9610                         ip += 5;
9611                         CHECK_OPSIZE (n * sizeof (guint32));
9612                         target = ip + n * sizeof (guint32);
9613
9614                         GET_BBLOCK (cfg, default_bblock, target);
9615                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9616
9617                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9618                         for (i = 0; i < n; ++i) {
9619                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9620                                 targets [i] = tblock;
9621                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9622                                 ip += 4;
9623                         }
9624
9625                         if (sp != stack_start) {
9626                                 /* 
9627                                  * Link the current bb with the targets as well, so handle_stack_args
9628                                  * will set their in_stack correctly.
9629                                  */
9630                                 link_bblock (cfg, cfg->cbb, default_bblock);
9631                                 for (i = 0; i < n; ++i)
9632                                         link_bblock (cfg, cfg->cbb, targets [i]);
9633
9634                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9635                                 sp = stack_start;
9636                                 CHECK_UNVERIFIABLE (cfg);
9637
9638                                 /* Undo the links */
9639                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9640                                 for (i = 0; i < n; ++i)
9641                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9642                         }
9643
9644                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9645                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9646
9647                         for (i = 0; i < n; ++i)
9648                                 link_bblock (cfg, cfg->cbb, targets [i]);
9649
9650                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9651                         table->table = targets;
9652                         table->table_size = n;
9653
9654                         use_op_switch = FALSE;
9655 #ifdef TARGET_ARM
9656                         /* ARM implements SWITCH statements differently */
9657                         /* FIXME: Make it use the generic implementation */
9658                         if (!cfg->compile_aot)
9659                                 use_op_switch = TRUE;
9660 #endif
9661
9662                         if (COMPILE_LLVM (cfg))
9663                                 use_op_switch = TRUE;
9664
9665                         cfg->cbb->has_jump_table = 1;
9666
9667                         if (use_op_switch) {
9668                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9669                                 ins->sreg1 = src1->dreg;
9670                                 ins->inst_p0 = table;
9671                                 ins->inst_many_bb = targets;
9672                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
9673                                 MONO_ADD_INS (cfg->cbb, ins);
9674                         } else {
9675                                 if (sizeof (gpointer) == 8)
9676                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9677                                 else
9678                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9679
9680 #if SIZEOF_REGISTER == 8
9681                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9682                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9683 #endif
9684
9685                                 if (cfg->compile_aot) {
9686                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9687                                 } else {
9688                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9689                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9690                                         ins->inst_p0 = table;
9691                                         ins->dreg = table_reg;
9692                                         MONO_ADD_INS (cfg->cbb, ins);
9693                                 }
9694
9695                                 /* FIXME: Use load_memindex */
9696                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9697                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9698                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9699                         }
9700                         start_new_bblock = 1;
9701                         inline_costs += (BRANCH_COST * 2);
9702                         break;
9703                 }
9704                 case CEE_LDIND_I1:
9705                 case CEE_LDIND_U1:
9706                 case CEE_LDIND_I2:
9707                 case CEE_LDIND_U2:
9708                 case CEE_LDIND_I4:
9709                 case CEE_LDIND_U4:
9710                 case CEE_LDIND_I8:
9711                 case CEE_LDIND_I:
9712                 case CEE_LDIND_R4:
9713                 case CEE_LDIND_R8:
9714                 case CEE_LDIND_REF:
9715                         CHECK_STACK (1);
9716                         --sp;
9717
9718                         switch (*ip) {
9719                         case CEE_LDIND_R4:
9720                         case CEE_LDIND_R8:
9721                                 dreg = alloc_freg (cfg);
9722                                 break;
9723                         case CEE_LDIND_I8:
9724                                 dreg = alloc_lreg (cfg);
9725                                 break;
9726                         case CEE_LDIND_REF:
9727                                 dreg = alloc_ireg_ref (cfg);
9728                                 break;
9729                         default:
9730                                 dreg = alloc_preg (cfg);
9731                         }
9732
9733                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9734                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9735                         if (*ip == CEE_LDIND_R4)
9736                                 ins->type = cfg->r4_stack_type;
9737                         ins->flags |= ins_flag;
9738                         MONO_ADD_INS (cfg->cbb, ins);
9739                         *sp++ = ins;
9740                         if (ins_flag & MONO_INST_VOLATILE) {
9741                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9742                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9743                         }
9744                         ins_flag = 0;
9745                         ++ip;
9746                         break;
9747                 case CEE_STIND_REF:
9748                 case CEE_STIND_I1:
9749                 case CEE_STIND_I2:
9750                 case CEE_STIND_I4:
9751                 case CEE_STIND_I8:
9752                 case CEE_STIND_R4:
9753                 case CEE_STIND_R8:
9754                 case CEE_STIND_I:
9755                         CHECK_STACK (2);
9756                         sp -= 2;
9757
9758                         if (ins_flag & MONO_INST_VOLATILE) {
9759                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9760                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9761                         }
9762
9763                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9764                         ins->flags |= ins_flag;
9765                         ins_flag = 0;
9766
9767                         MONO_ADD_INS (cfg->cbb, ins);
9768
9769                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
9770                                 emit_write_barrier (cfg, sp [0], sp [1]);
9771
9772                         inline_costs += 1;
9773                         ++ip;
9774                         break;
9775
9776                 case CEE_MUL:
9777                         CHECK_STACK (2);
9778
9779                         MONO_INST_NEW (cfg, ins, (*ip));
9780                         sp -= 2;
9781                         ins->sreg1 = sp [0]->dreg;
9782                         ins->sreg2 = sp [1]->dreg;
9783                         type_from_op (cfg, ins, sp [0], sp [1]);
9784                         CHECK_TYPE (ins);
9785                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9786
9787                         /* Use the immediate opcodes if possible */
9788                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9789                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9790                                 if (imm_opcode != -1) {
9791                                         ins->opcode = imm_opcode;
9792                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9793                                         ins->sreg2 = -1;
9794
9795                                         NULLIFY_INS (sp [1]);
9796                                 }
9797                         }
9798
9799                         MONO_ADD_INS ((cfg)->cbb, (ins));
9800
9801                         *sp++ = mono_decompose_opcode (cfg, ins);
9802                         ip++;
9803                         break;
9804                 case CEE_ADD:
9805                 case CEE_SUB:
9806                 case CEE_DIV:
9807                 case CEE_DIV_UN:
9808                 case CEE_REM:
9809                 case CEE_REM_UN:
9810                 case CEE_AND:
9811                 case CEE_OR:
9812                 case CEE_XOR:
9813                 case CEE_SHL:
9814                 case CEE_SHR:
9815                 case CEE_SHR_UN:
9816                         CHECK_STACK (2);
9817
9818                         MONO_INST_NEW (cfg, ins, (*ip));
9819                         sp -= 2;
9820                         ins->sreg1 = sp [0]->dreg;
9821                         ins->sreg2 = sp [1]->dreg;
9822                         type_from_op (cfg, ins, sp [0], sp [1]);
9823                         CHECK_TYPE (ins);
9824                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9825                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9826
9827                         /* FIXME: Pass opcode to is_inst_imm */
9828
9829                         /* Use the immediate opcodes if possible */
9830                         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)) {
9831                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9832                                 if (imm_opcode != -1) {
9833                                         ins->opcode = imm_opcode;
9834                                         if (sp [1]->opcode == OP_I8CONST) {
9835 #if SIZEOF_REGISTER == 8
9836                                                 ins->inst_imm = sp [1]->inst_l;
9837 #else
9838                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9839                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9840 #endif
9841                                         }
9842                                         else
9843                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9844                                         ins->sreg2 = -1;
9845
9846                                         /* Might be followed by an instruction added by add_widen_op */
9847                                         if (sp [1]->next == NULL)
9848                                                 NULLIFY_INS (sp [1]);
9849                                 }
9850                         }
9851                         MONO_ADD_INS ((cfg)->cbb, (ins));
9852
9853                         *sp++ = mono_decompose_opcode (cfg, ins);
9854                         ip++;
9855                         break;
9856                 case CEE_NEG:
9857                 case CEE_NOT:
9858                 case CEE_CONV_I1:
9859                 case CEE_CONV_I2:
9860                 case CEE_CONV_I4:
9861                 case CEE_CONV_R4:
9862                 case CEE_CONV_R8:
9863                 case CEE_CONV_U4:
9864                 case CEE_CONV_I8:
9865                 case CEE_CONV_U8:
9866                 case CEE_CONV_OVF_I8:
9867                 case CEE_CONV_OVF_U8:
9868                 case CEE_CONV_R_UN:
9869                         CHECK_STACK (1);
9870
9871                         /* Special case this earlier so we have long constants in the IR */
9872                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9873                                 int data = sp [-1]->inst_c0;
9874                                 sp [-1]->opcode = OP_I8CONST;
9875                                 sp [-1]->type = STACK_I8;
9876 #if SIZEOF_REGISTER == 8
9877                                 if ((*ip) == CEE_CONV_U8)
9878                                         sp [-1]->inst_c0 = (guint32)data;
9879                                 else
9880                                         sp [-1]->inst_c0 = data;
9881 #else
9882                                 sp [-1]->inst_ls_word = data;
9883                                 if ((*ip) == CEE_CONV_U8)
9884                                         sp [-1]->inst_ms_word = 0;
9885                                 else
9886                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9887 #endif
9888                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9889                         }
9890                         else {
9891                                 ADD_UNOP (*ip);
9892                         }
9893                         ip++;
9894                         break;
9895                 case CEE_CONV_OVF_I4:
9896                 case CEE_CONV_OVF_I1:
9897                 case CEE_CONV_OVF_I2:
9898                 case CEE_CONV_OVF_I:
9899                 case CEE_CONV_OVF_U:
9900                         CHECK_STACK (1);
9901
9902                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9903                                 ADD_UNOP (CEE_CONV_OVF_I8);
9904                                 ADD_UNOP (*ip);
9905                         } else {
9906                                 ADD_UNOP (*ip);
9907                         }
9908                         ip++;
9909                         break;
9910                 case CEE_CONV_OVF_U1:
9911                 case CEE_CONV_OVF_U2:
9912                 case CEE_CONV_OVF_U4:
9913                         CHECK_STACK (1);
9914
9915                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9916                                 ADD_UNOP (CEE_CONV_OVF_U8);
9917                                 ADD_UNOP (*ip);
9918                         } else {
9919                                 ADD_UNOP (*ip);
9920                         }
9921                         ip++;
9922                         break;
9923                 case CEE_CONV_OVF_I1_UN:
9924                 case CEE_CONV_OVF_I2_UN:
9925                 case CEE_CONV_OVF_I4_UN:
9926                 case CEE_CONV_OVF_I8_UN:
9927                 case CEE_CONV_OVF_U1_UN:
9928                 case CEE_CONV_OVF_U2_UN:
9929                 case CEE_CONV_OVF_U4_UN:
9930                 case CEE_CONV_OVF_U8_UN:
9931                 case CEE_CONV_OVF_I_UN:
9932                 case CEE_CONV_OVF_U_UN:
9933                 case CEE_CONV_U2:
9934                 case CEE_CONV_U1:
9935                 case CEE_CONV_I:
9936                 case CEE_CONV_U:
9937                         CHECK_STACK (1);
9938                         ADD_UNOP (*ip);
9939                         CHECK_CFG_EXCEPTION;
9940                         ip++;
9941                         break;
9942                 case CEE_ADD_OVF:
9943                 case CEE_ADD_OVF_UN:
9944                 case CEE_MUL_OVF:
9945                 case CEE_MUL_OVF_UN:
9946                 case CEE_SUB_OVF:
9947                 case CEE_SUB_OVF_UN:
9948                         CHECK_STACK (2);
9949                         ADD_BINOP (*ip);
9950                         ip++;
9951                         break;
9952                 case CEE_CPOBJ:
9953                         GSHAREDVT_FAILURE (*ip);
9954                         CHECK_OPSIZE (5);
9955                         CHECK_STACK (2);
9956                         token = read32 (ip + 1);
9957                         klass = mini_get_class (method, token, generic_context);
9958                         CHECK_TYPELOAD (klass);
9959                         sp -= 2;
9960                         if (generic_class_is_reference_type (cfg, klass)) {
9961                                 MonoInst *store, *load;
9962                                 int dreg = alloc_ireg_ref (cfg);
9963
9964                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9965                                 load->flags |= ins_flag;
9966                                 MONO_ADD_INS (cfg->cbb, load);
9967
9968                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9969                                 store->flags |= ins_flag;
9970                                 MONO_ADD_INS (cfg->cbb, store);
9971
9972                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9973                                         emit_write_barrier (cfg, sp [0], sp [1]);
9974                         } else {
9975                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9976                         }
9977                         ins_flag = 0;
9978                         ip += 5;
9979                         break;
9980                 case CEE_LDOBJ: {
9981                         int loc_index = -1;
9982                         int stloc_len = 0;
9983
9984                         CHECK_OPSIZE (5);
9985                         CHECK_STACK (1);
9986                         --sp;
9987                         token = read32 (ip + 1);
9988                         klass = mini_get_class (method, token, generic_context);
9989                         CHECK_TYPELOAD (klass);
9990
9991                         /* Optimize the common ldobj+stloc combination */
9992                         switch (ip [5]) {
9993                         case CEE_STLOC_S:
9994                                 loc_index = ip [6];
9995                                 stloc_len = 2;
9996                                 break;
9997                         case CEE_STLOC_0:
9998                         case CEE_STLOC_1:
9999                         case CEE_STLOC_2:
10000                         case CEE_STLOC_3:
10001                                 loc_index = ip [5] - CEE_STLOC_0;
10002                                 stloc_len = 1;
10003                                 break;
10004                         default:
10005                                 break;
10006                         }
10007
10008                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10009                                 CHECK_LOCAL (loc_index);
10010
10011                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10012                                 ins->dreg = cfg->locals [loc_index]->dreg;
10013                                 ins->flags |= ins_flag;
10014                                 ip += 5;
10015                                 ip += stloc_len;
10016                                 if (ins_flag & MONO_INST_VOLATILE) {
10017                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10018                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10019                                 }
10020                                 ins_flag = 0;
10021                                 break;
10022                         }
10023
10024                         /* Optimize the ldobj+stobj combination */
10025                         /* The reference case ends up being a load+store anyway */
10026                         /* Skip this if the operation is volatile. */
10027                         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)) {
10028                                 CHECK_STACK (1);
10029
10030                                 sp --;
10031
10032                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10033
10034                                 ip += 5 + 5;
10035                                 ins_flag = 0;
10036                                 break;
10037                         }
10038
10039                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10040                         ins->flags |= ins_flag;
10041                         *sp++ = ins;
10042
10043                         if (ins_flag & MONO_INST_VOLATILE) {
10044                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10045                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10046                         }
10047
10048                         ip += 5;
10049                         ins_flag = 0;
10050                         inline_costs += 1;
10051                         break;
10052                 }
10053                 case CEE_LDSTR:
10054                         CHECK_STACK_OVF (1);
10055                         CHECK_OPSIZE (5);
10056                         n = read32 (ip + 1);
10057
10058                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10059                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10060                                 ins->type = STACK_OBJ;
10061                                 *sp = ins;
10062                         }
10063                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10064                                 MonoInst *iargs [1];
10065                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10066
10067                                 if (cfg->compile_aot)
10068                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10069                                 else
10070                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10071                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10072                         } else {
10073                                 if (cfg->opt & MONO_OPT_SHARED) {
10074                                         MonoInst *iargs [3];
10075
10076                                         if (cfg->compile_aot) {
10077                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10078                                         }
10079                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10080                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10081                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10082                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10083                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10084                                         CHECK_CFG_ERROR;
10085                                 } else {
10086                                         if (cfg->cbb->out_of_line) {
10087                                                 MonoInst *iargs [2];
10088
10089                                                 if (image == mono_defaults.corlib) {
10090                                                         /* 
10091                                                          * Avoid relocations in AOT and save some space by using a 
10092                                                          * version of helper_ldstr specialized to mscorlib.
10093                                                          */
10094                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10095                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10096                                                 } else {
10097                                                         /* Avoid creating the string object */
10098                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10099                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10100                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10101                                                 }
10102                                         } 
10103                                         else
10104                                         if (cfg->compile_aot) {
10105                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10106                                                 *sp = ins;
10107                                                 MONO_ADD_INS (cfg->cbb, ins);
10108                                         } 
10109                                         else {
10110                                                 NEW_PCONST (cfg, ins, NULL);
10111                                                 ins->type = STACK_OBJ;
10112                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10113                                                 CHECK_CFG_ERROR;
10114                                                 
10115                                                 if (!ins->inst_p0)
10116                                                         OUT_OF_MEMORY_FAILURE;
10117
10118                                                 *sp = ins;
10119                                                 MONO_ADD_INS (cfg->cbb, ins);
10120                                         }
10121                                 }
10122                         }
10123
10124                         sp++;
10125                         ip += 5;
10126                         break;
10127                 case CEE_NEWOBJ: {
10128                         MonoInst *iargs [2];
10129                         MonoMethodSignature *fsig;
10130                         MonoInst this_ins;
10131                         MonoInst *alloc;
10132                         MonoInst *vtable_arg = NULL;
10133
10134                         CHECK_OPSIZE (5);
10135                         token = read32 (ip + 1);
10136                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10137                         CHECK_CFG_ERROR;
10138
10139                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10140                         CHECK_CFG_ERROR;
10141
10142                         mono_save_token_info (cfg, image, token, cmethod);
10143
10144                         if (!mono_class_init (cmethod->klass))
10145                                 TYPE_LOAD_ERROR (cmethod->klass);
10146
10147                         context_used = mini_method_check_context_used (cfg, cmethod);
10148
10149                         if (mono_security_core_clr_enabled ())
10150                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10151
10152                         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)) {
10153                                 emit_class_init (cfg, cmethod->klass);
10154                                 CHECK_TYPELOAD (cmethod->klass);
10155                         }
10156
10157                         /*
10158                         if (cfg->gsharedvt) {
10159                                 if (mini_is_gsharedvt_variable_signature (sig))
10160                                         GSHAREDVT_FAILURE (*ip);
10161                         }
10162                         */
10163
10164                         n = fsig->param_count;
10165                         CHECK_STACK (n);
10166
10167                         /* 
10168                          * Generate smaller code for the common newobj <exception> instruction in
10169                          * argument checking code.
10170                          */
10171                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10172                                 is_exception_class (cmethod->klass) && n <= 2 &&
10173                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10174                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10175                                 MonoInst *iargs [3];
10176
10177                                 sp -= n;
10178
10179                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10180                                 switch (n) {
10181                                 case 0:
10182                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10183                                         break;
10184                                 case 1:
10185                                         iargs [1] = sp [0];
10186                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10187                                         break;
10188                                 case 2:
10189                                         iargs [1] = sp [0];
10190                                         iargs [2] = sp [1];
10191                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10192                                         break;
10193                                 default:
10194                                         g_assert_not_reached ();
10195                                 }
10196
10197                                 ip += 5;
10198                                 inline_costs += 5;
10199                                 break;
10200                         }
10201
10202                         /* move the args to allow room for 'this' in the first position */
10203                         while (n--) {
10204                                 --sp;
10205                                 sp [1] = sp [0];
10206                         }
10207
10208                         /* check_call_signature () requires sp[0] to be set */
10209                         this_ins.type = STACK_OBJ;
10210                         sp [0] = &this_ins;
10211                         if (check_call_signature (cfg, fsig, sp))
10212                                 UNVERIFIED;
10213
10214                         iargs [0] = NULL;
10215
10216                         if (mini_class_is_system_array (cmethod->klass)) {
10217                                 *sp = emit_get_rgctx_method (cfg, context_used,
10218                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10219
10220                                 /* Avoid varargs in the common case */
10221                                 if (fsig->param_count == 1)
10222                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10223                                 else if (fsig->param_count == 2)
10224                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10225                                 else if (fsig->param_count == 3)
10226                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10227                                 else if (fsig->param_count == 4)
10228                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10229                                 else
10230                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10231                         } else if (cmethod->string_ctor) {
10232                                 g_assert (!context_used);
10233                                 g_assert (!vtable_arg);
10234                                 /* we simply pass a null pointer */
10235                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10236                                 /* now call the string ctor */
10237                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10238                         } else {
10239                                 if (cmethod->klass->valuetype) {
10240                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10241                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10242                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10243
10244                                         alloc = NULL;
10245
10246                                         /* 
10247                                          * The code generated by mini_emit_virtual_call () expects
10248                                          * iargs [0] to be a boxed instance, but luckily the vcall
10249                                          * will be transformed into a normal call there.
10250                                          */
10251                                 } else if (context_used) {
10252                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10253                                         *sp = alloc;
10254                                 } else {
10255                                         MonoVTable *vtable = NULL;
10256
10257                                         if (!cfg->compile_aot)
10258                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10259                                         CHECK_TYPELOAD (cmethod->klass);
10260
10261                                         /*
10262                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10263                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10264                                          * As a workaround, we call class cctors before allocating objects.
10265                                          */
10266                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10267                                                 emit_class_init (cfg, cmethod->klass);
10268                                                 if (cfg->verbose_level > 2)
10269                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10270                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10271                                         }
10272
10273                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10274                                         *sp = alloc;
10275                                 }
10276                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10277
10278                                 if (alloc)
10279                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10280
10281                                 /* Now call the actual ctor */
10282                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10283                                 CHECK_CFG_EXCEPTION;
10284                         }
10285
10286                         if (alloc == NULL) {
10287                                 /* Valuetype */
10288                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10289                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10290                                 *sp++= ins;
10291                         } else {
10292                                 *sp++ = alloc;
10293                         }
10294                         
10295                         ip += 5;
10296                         inline_costs += 5;
10297                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10298                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10299                         break;
10300                 }
10301                 case CEE_CASTCLASS:
10302                 case CEE_ISINST: {
10303                         CHECK_STACK (1);
10304                         --sp;
10305                         CHECK_OPSIZE (5);
10306                         token = read32 (ip + 1);
10307                         klass = mini_get_class (method, token, generic_context);
10308                         CHECK_TYPELOAD (klass);
10309                         if (sp [0]->type != STACK_OBJ)
10310                                 UNVERIFIED;
10311
10312                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
10313                         ins->dreg = alloc_preg (cfg);
10314                         ins->sreg1 = (*sp)->dreg;
10315                         ins->klass = klass;
10316                         ins->type = STACK_OBJ;
10317                         MONO_ADD_INS (cfg->cbb, ins);
10318
10319                         CHECK_CFG_EXCEPTION;
10320                         *sp++ = ins;
10321                         ip += 5;
10322
10323                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10324                         break;
10325                 }
10326                 case CEE_UNBOX_ANY: {
10327                         MonoInst *res, *addr;
10328
10329                         CHECK_STACK (1);
10330                         --sp;
10331                         CHECK_OPSIZE (5);
10332                         token = read32 (ip + 1);
10333                         klass = mini_get_class (method, token, generic_context);
10334                         CHECK_TYPELOAD (klass);
10335
10336                         mono_save_token_info (cfg, image, token, klass);
10337
10338                         context_used = mini_class_check_context_used (cfg, klass);
10339
10340                         if (mini_is_gsharedvt_klass (klass)) {
10341                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10342                                 inline_costs += 2;
10343                         } else if (generic_class_is_reference_type (cfg, klass)) {
10344                                 if (MONO_INS_IS_PCONST_NULL (*sp)) {
10345                                         EMIT_NEW_PCONST (cfg, res, NULL);
10346                                         res->type = STACK_OBJ;
10347                                 } else {
10348                                         MONO_INST_NEW (cfg, res, OP_CASTCLASS);
10349                                         res->dreg = alloc_preg (cfg);
10350                                         res->sreg1 = (*sp)->dreg;
10351                                         res->klass = klass;
10352                                         res->type = STACK_OBJ;
10353                                         MONO_ADD_INS (cfg->cbb, res);
10354                                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10355                                 }
10356                         } else if (mono_class_is_nullable (klass)) {
10357                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10358                         } else {
10359                                 addr = handle_unbox (cfg, klass, sp, context_used);
10360                                 /* LDOBJ */
10361                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10362                                 res = ins;
10363                                 inline_costs += 2;
10364                         }
10365
10366                         *sp ++ = res;
10367                         ip += 5;
10368                         break;
10369                 }
10370                 case CEE_BOX: {
10371                         MonoInst *val;
10372                         MonoClass *enum_class;
10373                         MonoMethod *has_flag;
10374
10375                         CHECK_STACK (1);
10376                         --sp;
10377                         val = *sp;
10378                         CHECK_OPSIZE (5);
10379                         token = read32 (ip + 1);
10380                         klass = mini_get_class (method, token, generic_context);
10381                         CHECK_TYPELOAD (klass);
10382
10383                         mono_save_token_info (cfg, image, token, klass);
10384
10385                         context_used = mini_class_check_context_used (cfg, klass);
10386
10387                         if (generic_class_is_reference_type (cfg, klass)) {
10388                                 *sp++ = val;
10389                                 ip += 5;
10390                                 break;
10391                         }
10392
10393                         if (klass == mono_defaults.void_class)
10394                                 UNVERIFIED;
10395                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10396                                 UNVERIFIED;
10397                         /* frequent check in generic code: box (struct), brtrue */
10398
10399                         /*
10400                          * Look for:
10401                          *
10402                          *   <push int/long ptr>
10403                          *   <push int/long>
10404                          *   box MyFlags
10405                          *   constrained. MyFlags
10406                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10407                          *
10408                          * If we find this sequence and the operand types on box and constrained
10409                          * are equal, we can emit a specialized instruction sequence instead of
10410                          * the very slow HasFlag () call.
10411                          */
10412                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10413                             /* Cheap checks first. */
10414                             ip + 5 + 6 + 5 < end &&
10415                             ip [5] == CEE_PREFIX1 &&
10416                             ip [6] == CEE_CONSTRAINED_ &&
10417                             ip [11] == CEE_CALLVIRT &&
10418                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10419                             mono_class_is_enum (klass) &&
10420                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10421                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10422                             has_flag->klass == mono_defaults.enum_class &&
10423                             !strcmp (has_flag->name, "HasFlag") &&
10424                             has_flag->signature->hasthis &&
10425                             has_flag->signature->param_count == 1) {
10426                                 CHECK_TYPELOAD (enum_class);
10427
10428                                 if (enum_class == klass) {
10429                                         MonoInst *enum_this, *enum_flag;
10430
10431                                         ip += 5 + 6 + 5;
10432                                         --sp;
10433
10434                                         enum_this = sp [0];
10435                                         enum_flag = sp [1];
10436
10437                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10438                                         break;
10439                                 }
10440                         }
10441
10442                         // FIXME: LLVM can't handle the inconsistent bb linking
10443                         if (!mono_class_is_nullable (klass) &&
10444                                 !mini_is_gsharedvt_klass (klass) &&
10445                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10446                                 (ip [5] == CEE_BRTRUE || 
10447                                  ip [5] == CEE_BRTRUE_S ||
10448                                  ip [5] == CEE_BRFALSE ||
10449                                  ip [5] == CEE_BRFALSE_S)) {
10450                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10451                                 int dreg;
10452                                 MonoBasicBlock *true_bb, *false_bb;
10453
10454                                 ip += 5;
10455
10456                                 if (cfg->verbose_level > 3) {
10457                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10458                                         printf ("<box+brtrue opt>\n");
10459                                 }
10460
10461                                 switch (*ip) {
10462                                 case CEE_BRTRUE_S:
10463                                 case CEE_BRFALSE_S:
10464                                         CHECK_OPSIZE (2);
10465                                         ip++;
10466                                         target = ip + 1 + (signed char)(*ip);
10467                                         ip++;
10468                                         break;
10469                                 case CEE_BRTRUE:
10470                                 case CEE_BRFALSE:
10471                                         CHECK_OPSIZE (5);
10472                                         ip++;
10473                                         target = ip + 4 + (gint)(read32 (ip));
10474                                         ip += 4;
10475                                         break;
10476                                 default:
10477                                         g_assert_not_reached ();
10478                                 }
10479
10480                                 /* 
10481                                  * We need to link both bblocks, since it is needed for handling stack
10482                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10483                                  * Branching to only one of them would lead to inconsistencies, so
10484                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10485                                  */
10486                                 GET_BBLOCK (cfg, true_bb, target);
10487                                 GET_BBLOCK (cfg, false_bb, ip);
10488
10489                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10490                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10491
10492                                 if (sp != stack_start) {
10493                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10494                                         sp = stack_start;
10495                                         CHECK_UNVERIFIABLE (cfg);
10496                                 }
10497
10498                                 if (COMPILE_LLVM (cfg)) {
10499                                         dreg = alloc_ireg (cfg);
10500                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10501                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10502
10503                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10504                                 } else {
10505                                         /* The JIT can't eliminate the iconst+compare */
10506                                         MONO_INST_NEW (cfg, ins, OP_BR);
10507                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10508                                         MONO_ADD_INS (cfg->cbb, ins);
10509                                 }
10510
10511                                 start_new_bblock = 1;
10512                                 break;
10513                         }
10514
10515                         *sp++ = handle_box (cfg, val, klass, context_used);
10516
10517                         CHECK_CFG_EXCEPTION;
10518                         ip += 5;
10519                         inline_costs += 1;
10520                         break;
10521                 }
10522                 case CEE_UNBOX: {
10523                         CHECK_STACK (1);
10524                         --sp;
10525                         CHECK_OPSIZE (5);
10526                         token = read32 (ip + 1);
10527                         klass = mini_get_class (method, token, generic_context);
10528                         CHECK_TYPELOAD (klass);
10529
10530                         mono_save_token_info (cfg, image, token, klass);
10531
10532                         context_used = mini_class_check_context_used (cfg, klass);
10533
10534                         if (mono_class_is_nullable (klass)) {
10535                                 MonoInst *val;
10536
10537                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10538                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10539
10540                                 *sp++= ins;
10541                         } else {
10542                                 ins = handle_unbox (cfg, klass, sp, context_used);
10543                                 *sp++ = ins;
10544                         }
10545                         ip += 5;
10546                         inline_costs += 2;
10547                         break;
10548                 }
10549                 case CEE_LDFLD:
10550                 case CEE_LDFLDA:
10551                 case CEE_STFLD:
10552                 case CEE_LDSFLD:
10553                 case CEE_LDSFLDA:
10554                 case CEE_STSFLD: {
10555                         MonoClassField *field;
10556 #ifndef DISABLE_REMOTING
10557                         int costs;
10558 #endif
10559                         guint foffset;
10560                         gboolean is_instance;
10561                         int op;
10562                         gpointer addr = NULL;
10563                         gboolean is_special_static;
10564                         MonoType *ftype;
10565                         MonoInst *store_val = NULL;
10566                         MonoInst *thread_ins;
10567
10568                         op = *ip;
10569                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10570                         if (is_instance) {
10571                                 if (op == CEE_STFLD) {
10572                                         CHECK_STACK (2);
10573                                         sp -= 2;
10574                                         store_val = sp [1];
10575                                 } else {
10576                                         CHECK_STACK (1);
10577                                         --sp;
10578                                 }
10579                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10580                                         UNVERIFIED;
10581                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10582                                         UNVERIFIED;
10583                         } else {
10584                                 if (op == CEE_STSFLD) {
10585                                         CHECK_STACK (1);
10586                                         sp--;
10587                                         store_val = sp [0];
10588                                 }
10589                         }
10590
10591                         CHECK_OPSIZE (5);
10592                         token = read32 (ip + 1);
10593                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10594                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
10595                                 klass = field->parent;
10596                         }
10597                         else {
10598                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10599                                 CHECK_CFG_ERROR;
10600                         }
10601                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10602                                 FIELD_ACCESS_FAILURE (method, field);
10603                         mono_class_init (klass);
10604
10605                         /* if the class is Critical then transparent code cannot access it's fields */
10606                         if (!is_instance && mono_security_core_clr_enabled ())
10607                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10608
10609                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10610                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10611                         if (mono_security_core_clr_enabled ())
10612                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10613                         */
10614
10615                         ftype = mono_field_get_type (field);
10616
10617                         /*
10618                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10619                          * the static case.
10620                          */
10621                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
10622                                 switch (op) {
10623                                 case CEE_LDFLD:
10624                                         op = CEE_LDSFLD;
10625                                         break;
10626                                 case CEE_STFLD:
10627                                         op = CEE_STSFLD;
10628                                         break;
10629                                 case CEE_LDFLDA:
10630                                         op = CEE_LDSFLDA;
10631                                         break;
10632                                 default:
10633                                         g_assert_not_reached ();
10634                                 }
10635                                 is_instance = FALSE;
10636                         }
10637
10638                         context_used = mini_class_check_context_used (cfg, klass);
10639
10640                         /* INSTANCE CASE */
10641
10642                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10643                         if (op == CEE_STFLD) {
10644                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10645                                         UNVERIFIED;
10646 #ifndef DISABLE_REMOTING
10647                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10648                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10649                                         MonoInst *iargs [5];
10650
10651                                         GSHAREDVT_FAILURE (op);
10652
10653                                         iargs [0] = sp [0];
10654                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10655                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10656                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10657                                                     field->offset);
10658                                         iargs [4] = sp [1];
10659
10660                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10661                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10662                                                                                            iargs, ip, cfg->real_offset, TRUE);
10663                                                 CHECK_CFG_EXCEPTION;
10664                                                 g_assert (costs > 0);
10665                                                       
10666                                                 cfg->real_offset += 5;
10667
10668                                                 inline_costs += costs;
10669                                         } else {
10670                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10671                                         }
10672                                 } else
10673 #endif
10674                                 {
10675                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
10676
10677                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10678
10679                                         if (ins_flag & MONO_INST_VOLATILE) {
10680                                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10681                                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10682                                         }
10683
10684                                         if (mini_is_gsharedvt_klass (klass)) {
10685                                                 MonoInst *offset_ins;
10686
10687                                                 context_used = mini_class_check_context_used (cfg, klass);
10688
10689                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10690                                                 /* The value is offset by 1 */
10691                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10692                                                 dreg = alloc_ireg_mp (cfg);
10693                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10694                                                 wbarrier_ptr_ins = ins;
10695                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10696                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10697                                         } else {
10698                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10699                                         }
10700                                         if (sp [0]->opcode != OP_LDADDR)
10701                                                 store->flags |= MONO_INST_FAULT;
10702
10703                                         if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
10704                                                 if (mini_is_gsharedvt_klass (klass)) {
10705                                                         g_assert (wbarrier_ptr_ins);
10706                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
10707                                                 } else {
10708                                                         /* insert call to write barrier */
10709                                                         MonoInst *ptr;
10710                                                         int dreg;
10711
10712                                                         dreg = alloc_ireg_mp (cfg);
10713                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10714                                                         emit_write_barrier (cfg, ptr, sp [1]);
10715                                                 }
10716                                         }
10717
10718                                         store->flags |= ins_flag;
10719                                 }
10720                                 ins_flag = 0;
10721                                 ip += 5;
10722                                 break;
10723                         }
10724
10725 #ifndef DISABLE_REMOTING
10726                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10727                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10728                                 MonoInst *iargs [4];
10729
10730                                 GSHAREDVT_FAILURE (op);
10731
10732                                 iargs [0] = sp [0];
10733                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10734                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10735                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10736                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10737                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10738                                                                                    iargs, ip, cfg->real_offset, TRUE);
10739                                         CHECK_CFG_EXCEPTION;
10740                                         g_assert (costs > 0);
10741                                                       
10742                                         cfg->real_offset += 5;
10743
10744                                         *sp++ = iargs [0];
10745
10746                                         inline_costs += costs;
10747                                 } else {
10748                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10749                                         *sp++ = ins;
10750                                 }
10751                         } else 
10752 #endif
10753                         if (is_instance) {
10754                                 if (sp [0]->type == STACK_VTYPE) {
10755                                         MonoInst *var;
10756
10757                                         /* Have to compute the address of the variable */
10758
10759                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10760                                         if (!var)
10761                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10762                                         else
10763                                                 g_assert (var->klass == klass);
10764                                         
10765                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10766                                         sp [0] = ins;
10767                                 }
10768
10769                                 if (op == CEE_LDFLDA) {
10770                                         if (sp [0]->type == STACK_OBJ) {
10771                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10772                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10773                                         }
10774
10775                                         dreg = alloc_ireg_mp (cfg);
10776
10777                                         if (mini_is_gsharedvt_klass (klass)) {
10778                                                 MonoInst *offset_ins;
10779
10780                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10781                                                 /* The value is offset by 1 */
10782                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10783                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10784                                         } else {
10785                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10786                                         }
10787                                         ins->klass = mono_class_from_mono_type (field->type);
10788                                         ins->type = STACK_MP;
10789                                         *sp++ = ins;
10790                                 } else {
10791                                         MonoInst *load;
10792
10793                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10794
10795                                         if (sp [0]->opcode == OP_LDADDR && klass->simd_type && cfg->opt & MONO_OPT_SIMD) {
10796                                                 ins = mono_emit_simd_field_load (cfg, field, sp [0]);
10797                                                 if (ins) {
10798                                                         *sp++ = ins;
10799                                                         ins_flag = 0;
10800                                                         ip += 5;
10801                                                         break;
10802                                                 }
10803                                         }
10804
10805                                         if (mini_is_gsharedvt_klass (klass)) {
10806                                                 MonoInst *offset_ins;
10807
10808                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10809                                                 /* The value is offset by 1 */
10810                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10811                                                 dreg = alloc_ireg_mp (cfg);
10812                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10813                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10814                                         } else {
10815                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10816                                         }
10817                                         load->flags |= ins_flag;
10818                                         if (sp [0]->opcode != OP_LDADDR)
10819                                                 load->flags |= MONO_INST_FAULT;
10820                                         *sp++ = load;
10821                                 }
10822                         }
10823
10824                         if (is_instance) {
10825                                 ins_flag = 0;
10826                                 ip += 5;
10827                                 break;
10828                         }
10829
10830                         /* STATIC CASE */
10831                         context_used = mini_class_check_context_used (cfg, klass);
10832
10833                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
10834                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
10835                                 CHECK_CFG_ERROR;
10836                         }
10837
10838                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10839                          * to be called here.
10840                          */
10841                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10842                                 mono_class_vtable (cfg->domain, klass);
10843                                 CHECK_TYPELOAD (klass);
10844                         }
10845                         mono_domain_lock (cfg->domain);
10846                         if (cfg->domain->special_static_fields)
10847                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10848                         mono_domain_unlock (cfg->domain);
10849
10850                         is_special_static = mono_class_field_is_special_static (field);
10851
10852                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10853                                 thread_ins = mono_create_tls_get (cfg, TLS_KEY_THREAD);
10854                         else
10855                                 thread_ins = NULL;
10856
10857                         /* Generate IR to compute the field address */
10858                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10859                                 /*
10860                                  * Fast access to TLS data
10861                                  * Inline version of get_thread_static_data () in
10862                                  * threads.c.
10863                                  */
10864                                 guint32 offset;
10865                                 int idx, static_data_reg, array_reg, dreg;
10866
10867                                 if (context_used && cfg->gsharedvt && mini_is_gsharedvt_klass (klass))
10868                                         GSHAREDVT_FAILURE (op);
10869
10870                                 static_data_reg = alloc_ireg (cfg);
10871                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
10872
10873                                 if (cfg->compile_aot) {
10874                                         int offset_reg, offset2_reg, idx_reg;
10875
10876                                         /* For TLS variables, this will return the TLS offset */
10877                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10878                                         offset_reg = ins->dreg;
10879                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10880                                         idx_reg = alloc_ireg (cfg);
10881                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
10882                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10883                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10884                                         array_reg = alloc_ireg (cfg);
10885                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10886                                         offset2_reg = alloc_ireg (cfg);
10887                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
10888                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
10889                                         dreg = alloc_ireg (cfg);
10890                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10891                                 } else {
10892                                         offset = (gsize)addr & 0x7fffffff;
10893                                         idx = offset & 0x3f;
10894
10895                                         array_reg = alloc_ireg (cfg);
10896                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10897                                         dreg = alloc_ireg (cfg);
10898                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
10899                                 }
10900                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10901                                         (cfg->compile_aot && is_special_static) ||
10902                                         (context_used && is_special_static)) {
10903                                 MonoInst *iargs [2];
10904
10905                                 g_assert (field->parent);
10906                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10907                                 if (context_used) {
10908                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10909                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10910                                 } else {
10911                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10912                                 }
10913                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10914                         } else if (context_used) {
10915                                 MonoInst *static_data;
10916
10917                                 /*
10918                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10919                                         method->klass->name_space, method->klass->name, method->name,
10920                                         depth, field->offset);
10921                                 */
10922
10923                                 if (mono_class_needs_cctor_run (klass, method))
10924                                         emit_class_init (cfg, klass);
10925
10926                                 /*
10927                                  * The pointer we're computing here is
10928                                  *
10929                                  *   super_info.static_data + field->offset
10930                                  */
10931                                 static_data = mini_emit_get_rgctx_klass (cfg, context_used,
10932                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10933
10934                                 if (mini_is_gsharedvt_klass (klass)) {
10935                                         MonoInst *offset_ins;
10936
10937                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10938                                         /* The value is offset by 1 */
10939                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10940                                         dreg = alloc_ireg_mp (cfg);
10941                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10942                                 } else if (field->offset == 0) {
10943                                         ins = static_data;
10944                                 } else {
10945                                         int addr_reg = mono_alloc_preg (cfg);
10946                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10947                                 }
10948                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10949                                 MonoInst *iargs [2];
10950
10951                                 g_assert (field->parent);
10952                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10953                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10954                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10955                         } else {
10956                                 MonoVTable *vtable = NULL;
10957
10958                                 if (!cfg->compile_aot)
10959                                         vtable = mono_class_vtable (cfg->domain, klass);
10960                                 CHECK_TYPELOAD (klass);
10961
10962                                 if (!addr) {
10963                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10964                                                 if (!(g_slist_find (class_inits, klass))) {
10965                                                         emit_class_init (cfg, klass);
10966                                                         if (cfg->verbose_level > 2)
10967                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10968                                                         class_inits = g_slist_prepend (class_inits, klass);
10969                                                 }
10970                                         } else {
10971                                                 if (cfg->run_cctors) {
10972                                                         /* This makes so that inline cannot trigger */
10973                                                         /* .cctors: too many apps depend on them */
10974                                                         /* running with a specific order... */
10975                                                         g_assert (vtable);
10976                                                         if (! vtable->initialized)
10977                                                                 INLINE_FAILURE ("class init");
10978                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
10979                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
10980                                                                 goto exception_exit;
10981                                                         }
10982                                                 }
10983                                         }
10984                                         if (cfg->compile_aot)
10985                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10986                                         else {
10987                                                 g_assert (vtable);
10988                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10989                                                 g_assert (addr);
10990                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10991                                         }
10992                                 } else {
10993                                         MonoInst *iargs [1];
10994                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10995                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10996                                 }
10997                         }
10998
10999                         /* Generate IR to do the actual load/store operation */
11000
11001                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11002                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11003                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11004                         }
11005
11006                         if (op == CEE_LDSFLDA) {
11007                                 ins->klass = mono_class_from_mono_type (ftype);
11008                                 ins->type = STACK_PTR;
11009                                 *sp++ = ins;
11010                         } else if (op == CEE_STSFLD) {
11011                                 MonoInst *store;
11012
11013                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11014                                 store->flags |= ins_flag;
11015                         } else {
11016                                 gboolean is_const = FALSE;
11017                                 MonoVTable *vtable = NULL;
11018                                 gpointer addr = NULL;
11019
11020                                 if (!context_used) {
11021                                         vtable = mono_class_vtable (cfg->domain, klass);
11022                                         CHECK_TYPELOAD (klass);
11023                                 }
11024                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11025                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11026                                         int ro_type = ftype->type;
11027                                         if (!addr)
11028                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11029                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11030                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11031                                         }
11032
11033                                         GSHAREDVT_FAILURE (op);
11034
11035                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11036                                         is_const = TRUE;
11037                                         switch (ro_type) {
11038                                         case MONO_TYPE_BOOLEAN:
11039                                         case MONO_TYPE_U1:
11040                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11041                                                 sp++;
11042                                                 break;
11043                                         case MONO_TYPE_I1:
11044                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11045                                                 sp++;
11046                                                 break;                                          
11047                                         case MONO_TYPE_CHAR:
11048                                         case MONO_TYPE_U2:
11049                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11050                                                 sp++;
11051                                                 break;
11052                                         case MONO_TYPE_I2:
11053                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11054                                                 sp++;
11055                                                 break;
11056                                                 break;
11057                                         case MONO_TYPE_I4:
11058                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11059                                                 sp++;
11060                                                 break;                                          
11061                                         case MONO_TYPE_U4:
11062                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11063                                                 sp++;
11064                                                 break;
11065                                         case MONO_TYPE_I:
11066                                         case MONO_TYPE_U:
11067                                         case MONO_TYPE_PTR:
11068                                         case MONO_TYPE_FNPTR:
11069                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11070                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11071                                                 sp++;
11072                                                 break;
11073                                         case MONO_TYPE_STRING:
11074                                         case MONO_TYPE_OBJECT:
11075                                         case MONO_TYPE_CLASS:
11076                                         case MONO_TYPE_SZARRAY:
11077                                         case MONO_TYPE_ARRAY:
11078                                                 if (!mono_gc_is_moving ()) {
11079                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11080                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11081                                                         sp++;
11082                                                 } else {
11083                                                         is_const = FALSE;
11084                                                 }
11085                                                 break;
11086                                         case MONO_TYPE_I8:
11087                                         case MONO_TYPE_U8:
11088                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11089                                                 sp++;
11090                                                 break;
11091                                         case MONO_TYPE_R4:
11092                                         case MONO_TYPE_R8:
11093                                         case MONO_TYPE_VALUETYPE:
11094                                         default:
11095                                                 is_const = FALSE;
11096                                                 break;
11097                                         }
11098                                 }
11099
11100                                 if (!is_const) {
11101                                         MonoInst *load;
11102
11103                                         CHECK_STACK_OVF (1);
11104
11105                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11106                                         load->flags |= ins_flag;
11107                                         ins_flag = 0;
11108                                         *sp++ = load;
11109                                 }
11110                         }
11111
11112                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11113                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11114                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11115                         }
11116
11117                         ins_flag = 0;
11118                         ip += 5;
11119                         break;
11120                 }
11121                 case CEE_STOBJ:
11122                         CHECK_STACK (2);
11123                         sp -= 2;
11124                         CHECK_OPSIZE (5);
11125                         token = read32 (ip + 1);
11126                         klass = mini_get_class (method, token, generic_context);
11127                         CHECK_TYPELOAD (klass);
11128                         if (ins_flag & MONO_INST_VOLATILE) {
11129                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11130                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11131                         }
11132                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11133                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11134                         ins->flags |= ins_flag;
11135                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11136                                 generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
11137                                 /* insert call to write barrier */
11138                                 emit_write_barrier (cfg, sp [0], sp [1]);
11139                         }
11140                         ins_flag = 0;
11141                         ip += 5;
11142                         inline_costs += 1;
11143                         break;
11144
11145                         /*
11146                          * Array opcodes
11147                          */
11148                 case CEE_NEWARR: {
11149                         MonoInst *len_ins;
11150                         const char *data_ptr;
11151                         int data_size = 0;
11152                         guint32 field_token;
11153
11154                         CHECK_STACK (1);
11155                         --sp;
11156
11157                         CHECK_OPSIZE (5);
11158                         token = read32 (ip + 1);
11159
11160                         klass = mini_get_class (method, token, generic_context);
11161                         CHECK_TYPELOAD (klass);
11162
11163                         context_used = mini_class_check_context_used (cfg, klass);
11164
11165                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11166                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11167                                 ins->sreg1 = sp [0]->dreg;
11168                                 ins->type = STACK_I4;
11169                                 ins->dreg = alloc_ireg (cfg);
11170                                 MONO_ADD_INS (cfg->cbb, ins);
11171                                 *sp = mono_decompose_opcode (cfg, ins);
11172                         }
11173
11174                         if (context_used) {
11175                                 MonoInst *args [3];
11176                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11177                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11178
11179                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11180
11181                                 /* vtable */
11182                                 args [0] = mini_emit_get_rgctx_klass (cfg, context_used,
11183                                         array_class, MONO_RGCTX_INFO_VTABLE);
11184                                 /* array len */
11185                                 args [1] = sp [0];
11186
11187                                 if (managed_alloc)
11188                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11189                                 else
11190                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11191                         } else {
11192                                 if (cfg->opt & MONO_OPT_SHARED) {
11193                                         /* Decompose now to avoid problems with references to the domainvar */
11194                                         MonoInst *iargs [3];
11195
11196                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11197                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11198                                         iargs [2] = sp [0];
11199
11200                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11201                                 } else {
11202                                         /* Decompose later since it is needed by abcrem */
11203                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11204                                         mono_class_vtable (cfg->domain, array_type);
11205                                         CHECK_TYPELOAD (array_type);
11206
11207                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11208                                         ins->dreg = alloc_ireg_ref (cfg);
11209                                         ins->sreg1 = sp [0]->dreg;
11210                                         ins->inst_newa_class = klass;
11211                                         ins->type = STACK_OBJ;
11212                                         ins->klass = array_type;
11213                                         MONO_ADD_INS (cfg->cbb, ins);
11214                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11215                                         cfg->cbb->has_array_access = TRUE;
11216
11217                                         /* Needed so mono_emit_load_get_addr () gets called */
11218                                         mono_get_got_var (cfg);
11219                                 }
11220                         }
11221
11222                         len_ins = sp [0];
11223                         ip += 5;
11224                         *sp++ = ins;
11225                         inline_costs += 1;
11226
11227                         /* 
11228                          * we inline/optimize the initialization sequence if possible.
11229                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11230                          * for small sizes open code the memcpy
11231                          * ensure the rva field is big enough
11232                          */
11233                         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))) {
11234                                 MonoMethod *memcpy_method = get_memcpy_method ();
11235                                 MonoInst *iargs [3];
11236                                 int add_reg = alloc_ireg_mp (cfg);
11237
11238                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11239                                 if (cfg->compile_aot) {
11240                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11241                                 } else {
11242                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11243                                 }
11244                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11245                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11246                                 ip += 11;
11247                         }
11248
11249                         break;
11250                 }
11251                 case CEE_LDLEN:
11252                         CHECK_STACK (1);
11253                         --sp;
11254                         if (sp [0]->type != STACK_OBJ)
11255                                 UNVERIFIED;
11256
11257                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11258                         ins->dreg = alloc_preg (cfg);
11259                         ins->sreg1 = sp [0]->dreg;
11260                         ins->type = STACK_I4;
11261                         /* This flag will be inherited by the decomposition */
11262                         ins->flags |= MONO_INST_FAULT;
11263                         MONO_ADD_INS (cfg->cbb, ins);
11264                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11265                         cfg->cbb->has_array_access = TRUE;
11266                         ip ++;
11267                         *sp++ = ins;
11268                         break;
11269                 case CEE_LDELEMA:
11270                         CHECK_STACK (2);
11271                         sp -= 2;
11272                         CHECK_OPSIZE (5);
11273                         if (sp [0]->type != STACK_OBJ)
11274                                 UNVERIFIED;
11275
11276                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11277
11278                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11279                         CHECK_TYPELOAD (klass);
11280                         /* we need to make sure that this array is exactly the type it needs
11281                          * to be for correctness. the wrappers are lax with their usage
11282                          * so we need to ignore them here
11283                          */
11284                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11285                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11286                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11287                                 CHECK_TYPELOAD (array_class);
11288                         }
11289
11290                         readonly = FALSE;
11291                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11292                         *sp++ = ins;
11293                         ip += 5;
11294                         break;
11295                 case CEE_LDELEM:
11296                 case CEE_LDELEM_I1:
11297                 case CEE_LDELEM_U1:
11298                 case CEE_LDELEM_I2:
11299                 case CEE_LDELEM_U2:
11300                 case CEE_LDELEM_I4:
11301                 case CEE_LDELEM_U4:
11302                 case CEE_LDELEM_I8:
11303                 case CEE_LDELEM_I:
11304                 case CEE_LDELEM_R4:
11305                 case CEE_LDELEM_R8:
11306                 case CEE_LDELEM_REF: {
11307                         MonoInst *addr;
11308
11309                         CHECK_STACK (2);
11310                         sp -= 2;
11311
11312                         if (*ip == CEE_LDELEM) {
11313                                 CHECK_OPSIZE (5);
11314                                 token = read32 (ip + 1);
11315                                 klass = mini_get_class (method, token, generic_context);
11316                                 CHECK_TYPELOAD (klass);
11317                                 mono_class_init (klass);
11318                         }
11319                         else
11320                                 klass = array_access_to_klass (*ip);
11321
11322                         if (sp [0]->type != STACK_OBJ)
11323                                 UNVERIFIED;
11324
11325                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11326
11327                         if (mini_is_gsharedvt_variable_klass (klass)) {
11328                                 // FIXME-VT: OP_ICONST optimization
11329                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11330                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11331                                 ins->opcode = OP_LOADV_MEMBASE;
11332                         } else if (sp [1]->opcode == OP_ICONST) {
11333                                 int array_reg = sp [0]->dreg;
11334                                 int index_reg = sp [1]->dreg;
11335                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11336
11337                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
11338                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
11339
11340                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11341                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11342                         } else {
11343                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11344                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11345                         }
11346                         *sp++ = ins;
11347                         if (*ip == CEE_LDELEM)
11348                                 ip += 5;
11349                         else
11350                                 ++ip;
11351                         break;
11352                 }
11353                 case CEE_STELEM_I:
11354                 case CEE_STELEM_I1:
11355                 case CEE_STELEM_I2:
11356                 case CEE_STELEM_I4:
11357                 case CEE_STELEM_I8:
11358                 case CEE_STELEM_R4:
11359                 case CEE_STELEM_R8:
11360                 case CEE_STELEM_REF:
11361                 case CEE_STELEM: {
11362                         CHECK_STACK (3);
11363                         sp -= 3;
11364
11365                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11366
11367                         if (*ip == CEE_STELEM) {
11368                                 CHECK_OPSIZE (5);
11369                                 token = read32 (ip + 1);
11370                                 klass = mini_get_class (method, token, generic_context);
11371                                 CHECK_TYPELOAD (klass);
11372                                 mono_class_init (klass);
11373                         }
11374                         else
11375                                 klass = array_access_to_klass (*ip);
11376
11377                         if (sp [0]->type != STACK_OBJ)
11378                                 UNVERIFIED;
11379
11380                         emit_array_store (cfg, klass, sp, TRUE);
11381
11382                         if (*ip == CEE_STELEM)
11383                                 ip += 5;
11384                         else
11385                                 ++ip;
11386                         inline_costs += 1;
11387                         break;
11388                 }
11389                 case CEE_CKFINITE: {
11390                         CHECK_STACK (1);
11391                         --sp;
11392
11393                         if (cfg->llvm_only) {
11394                                 MonoInst *iargs [1];
11395
11396                                 iargs [0] = sp [0];
11397                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11398                         } else  {
11399                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11400                                 ins->sreg1 = sp [0]->dreg;
11401                                 ins->dreg = alloc_freg (cfg);
11402                                 ins->type = STACK_R8;
11403                                 MONO_ADD_INS (cfg->cbb, ins);
11404
11405                                 *sp++ = mono_decompose_opcode (cfg, ins);
11406                         }
11407
11408                         ++ip;
11409                         break;
11410                 }
11411                 case CEE_REFANYVAL: {
11412                         MonoInst *src_var, *src;
11413
11414                         int klass_reg = alloc_preg (cfg);
11415                         int dreg = alloc_preg (cfg);
11416
11417                         GSHAREDVT_FAILURE (*ip);
11418
11419                         CHECK_STACK (1);
11420                         MONO_INST_NEW (cfg, ins, *ip);
11421                         --sp;
11422                         CHECK_OPSIZE (5);
11423                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11424                         CHECK_TYPELOAD (klass);
11425
11426                         context_used = mini_class_check_context_used (cfg, klass);
11427
11428                         // FIXME:
11429                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11430                         if (!src_var)
11431                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11432                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11433                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11434
11435                         if (context_used) {
11436                                 MonoInst *klass_ins;
11437
11438                                 klass_ins = mini_emit_get_rgctx_klass (cfg, context_used,
11439                                                 klass, MONO_RGCTX_INFO_KLASS);
11440
11441                                 // FIXME:
11442                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11443                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11444                         } else {
11445                                 mini_emit_class_check (cfg, klass_reg, klass);
11446                         }
11447                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11448                         ins->type = STACK_MP;
11449                         ins->klass = klass;
11450                         *sp++ = ins;
11451                         ip += 5;
11452                         break;
11453                 }
11454                 case CEE_MKREFANY: {
11455                         MonoInst *loc, *addr;
11456
11457                         GSHAREDVT_FAILURE (*ip);
11458
11459                         CHECK_STACK (1);
11460                         MONO_INST_NEW (cfg, ins, *ip);
11461                         --sp;
11462                         CHECK_OPSIZE (5);
11463                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11464                         CHECK_TYPELOAD (klass);
11465
11466                         context_used = mini_class_check_context_used (cfg, klass);
11467
11468                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11469                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11470
11471                         if (context_used) {
11472                                 MonoInst *const_ins;
11473                                 int type_reg = alloc_preg (cfg);
11474
11475                                 const_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11476                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11477                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11478                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11479                         } else {
11480                                 int const_reg = alloc_preg (cfg);
11481                                 int type_reg = alloc_preg (cfg);
11482
11483                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11484                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11485                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11486                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11487                         }
11488                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11489
11490                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11491                         ins->type = STACK_VTYPE;
11492                         ins->klass = mono_defaults.typed_reference_class;
11493                         *sp++ = ins;
11494                         ip += 5;
11495                         break;
11496                 }
11497                 case CEE_LDTOKEN: {
11498                         gpointer handle;
11499                         MonoClass *handle_class;
11500
11501                         CHECK_STACK_OVF (1);
11502
11503                         CHECK_OPSIZE (5);
11504                         n = read32 (ip + 1);
11505
11506                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11507                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11508                                 handle = mono_method_get_wrapper_data (method, n);
11509                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
11510                                 if (handle_class == mono_defaults.typehandle_class)
11511                                         handle = &((MonoClass*)handle)->byval_arg;
11512                         }
11513                         else {
11514                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11515                                 CHECK_CFG_ERROR;
11516                         }
11517                         if (!handle)
11518                                 LOAD_ERROR;
11519                         mono_class_init (handle_class);
11520                         if (cfg->gshared) {
11521                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11522                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11523                                         /* This case handles ldtoken
11524                                            of an open type, like for
11525                                            typeof(Gen<>). */
11526                                         context_used = 0;
11527                                 } else if (handle_class == mono_defaults.typehandle_class) {
11528                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
11529                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11530                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11531                                 else if (handle_class == mono_defaults.methodhandle_class)
11532                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
11533                                 else
11534                                         g_assert_not_reached ();
11535                         }
11536
11537                         if ((cfg->opt & MONO_OPT_SHARED) &&
11538                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11539                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11540                                 MonoInst *addr, *vtvar, *iargs [3];
11541                                 int method_context_used;
11542
11543                                 method_context_used = mini_method_check_context_used (cfg, method);
11544
11545                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11546
11547                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11548                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11549                                 if (method_context_used) {
11550                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11551                                                 method, MONO_RGCTX_INFO_METHOD);
11552                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11553                                 } else {
11554                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11555                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11556                                 }
11557                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11558
11559                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11560
11561                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11562                         } else {
11563                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11564                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11565                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11566                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11567                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11568                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
11569
11570                                         mono_class_init (tclass);
11571                                         if (context_used) {
11572                                                 ins = mini_emit_get_rgctx_klass (cfg, context_used,
11573                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11574                                         } else if (cfg->compile_aot) {
11575                                                 if (method->wrapper_type) {
11576                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11577                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11578                                                                 /* Special case for static synchronized wrappers */
11579                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11580                                                         } else {
11581                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11582                                                                 /* FIXME: n is not a normal token */
11583                                                                 DISABLE_AOT (cfg);
11584                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11585                                                         }
11586                                                 } else {
11587                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11588                                                 }
11589                                         } else {
11590                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
11591                                                 CHECK_CFG_ERROR;
11592                                                 EMIT_NEW_PCONST (cfg, ins, rt);
11593                                         }
11594                                         ins->type = STACK_OBJ;
11595                                         ins->klass = cmethod->klass;
11596                                         ip += 5;
11597                                 } else {
11598                                         MonoInst *addr, *vtvar;
11599
11600                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11601
11602                                         if (context_used) {
11603                                                 if (handle_class == mono_defaults.typehandle_class) {
11604                                                         ins = mini_emit_get_rgctx_klass (cfg, context_used,
11605                                                                         mono_class_from_mono_type ((MonoType *)handle),
11606                                                                         MONO_RGCTX_INFO_TYPE);
11607                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11608                                                         ins = emit_get_rgctx_method (cfg, context_used,
11609                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
11610                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11611                                                         ins = emit_get_rgctx_field (cfg, context_used,
11612                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
11613                                                 } else {
11614                                                         g_assert_not_reached ();
11615                                                 }
11616                                         } else if (cfg->compile_aot) {
11617                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11618                                         } else {
11619                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11620                                         }
11621                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11622                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11623                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11624                                 }
11625                         }
11626
11627                         *sp++ = ins;
11628                         ip += 5;
11629                         break;
11630                 }
11631                 case CEE_THROW:
11632                         CHECK_STACK (1);
11633                         if (sp [-1]->type != STACK_OBJ)
11634                                 UNVERIFIED;
11635
11636                         MONO_INST_NEW (cfg, ins, OP_THROW);
11637                         --sp;
11638                         ins->sreg1 = sp [0]->dreg;
11639                         ip++;
11640                         cfg->cbb->out_of_line = TRUE;
11641                         MONO_ADD_INS (cfg->cbb, ins);
11642                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11643                         MONO_ADD_INS (cfg->cbb, ins);
11644                         sp = stack_start;
11645                         
11646                         link_bblock (cfg, cfg->cbb, end_bblock);
11647                         start_new_bblock = 1;
11648                         /* This can complicate code generation for llvm since the return value might not be defined */
11649                         if (COMPILE_LLVM (cfg))
11650                                 INLINE_FAILURE ("throw");
11651                         break;
11652                 case CEE_ENDFINALLY:
11653                         if (!ip_in_finally_clause (cfg, ip - header->code))
11654                                 UNVERIFIED;
11655                         /* mono_save_seq_point_info () depends on this */
11656                         if (sp != stack_start)
11657                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11658                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11659                         MONO_ADD_INS (cfg->cbb, ins);
11660                         ip++;
11661                         start_new_bblock = 1;
11662
11663                         /*
11664                          * Control will leave the method so empty the stack, otherwise
11665                          * the next basic block will start with a nonempty stack.
11666                          */
11667                         while (sp != stack_start) {
11668                                 sp--;
11669                         }
11670                         break;
11671                 case CEE_LEAVE:
11672                 case CEE_LEAVE_S: {
11673                         GList *handlers;
11674
11675                         if (*ip == CEE_LEAVE) {
11676                                 CHECK_OPSIZE (5);
11677                                 target = ip + 5 + (gint32)read32(ip + 1);
11678                         } else {
11679                                 CHECK_OPSIZE (2);
11680                                 target = ip + 2 + (signed char)(ip [1]);
11681                         }
11682
11683                         /* empty the stack */
11684                         while (sp != stack_start) {
11685                                 sp--;
11686                         }
11687
11688                         /* 
11689                          * If this leave statement is in a catch block, check for a
11690                          * pending exception, and rethrow it if necessary.
11691                          * We avoid doing this in runtime invoke wrappers, since those are called
11692                          * by native code which excepts the wrapper to catch all exceptions.
11693                          */
11694                         for (i = 0; i < header->num_clauses; ++i) {
11695                                 MonoExceptionClause *clause = &header->clauses [i];
11696
11697                                 /* 
11698                                  * Use <= in the final comparison to handle clauses with multiple
11699                                  * leave statements, like in bug #78024.
11700                                  * The ordering of the exception clauses guarantees that we find the
11701                                  * innermost clause.
11702                                  */
11703                                 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) {
11704                                         MonoInst *exc_ins;
11705                                         MonoBasicBlock *dont_throw;
11706
11707                                         /*
11708                                           MonoInst *load;
11709
11710                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11711                                         */
11712
11713                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11714
11715                                         NEW_BBLOCK (cfg, dont_throw);
11716
11717                                         /*
11718                                          * Currently, we always rethrow the abort exception, despite the 
11719                                          * fact that this is not correct. See thread6.cs for an example. 
11720                                          * But propagating the abort exception is more important than 
11721                                          * getting the sematics right.
11722                                          */
11723                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11724                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11725                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11726
11727                                         MONO_START_BB (cfg, dont_throw);
11728                                 }
11729                         }
11730
11731 #ifdef ENABLE_LLVM
11732                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
11733 #endif
11734
11735                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11736                                 GList *tmp;
11737                                 MonoExceptionClause *clause;
11738
11739                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11740                                         clause = (MonoExceptionClause *)tmp->data;
11741                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11742                                         g_assert (tblock);
11743                                         link_bblock (cfg, cfg->cbb, tblock);
11744                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11745                                         ins->inst_target_bb = tblock;
11746                                         ins->inst_eh_block = clause;
11747                                         MONO_ADD_INS (cfg->cbb, ins);
11748                                         cfg->cbb->has_call_handler = 1;
11749                                         if (COMPILE_LLVM (cfg)) {
11750                                                 MonoBasicBlock *target_bb;
11751
11752                                                 /* 
11753                                                  * Link the finally bblock with the target, since it will
11754                                                  * conceptually branch there.
11755                                                  */
11756                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
11757                                                 GET_BBLOCK (cfg, target_bb, target);
11758                                                 link_bblock (cfg, tblock, target_bb);
11759                                         }
11760                                 }
11761                                 g_list_free (handlers);
11762                         } 
11763
11764                         MONO_INST_NEW (cfg, ins, OP_BR);
11765                         MONO_ADD_INS (cfg->cbb, ins);
11766                         GET_BBLOCK (cfg, tblock, target);
11767                         link_bblock (cfg, cfg->cbb, tblock);
11768                         ins->inst_target_bb = tblock;
11769
11770                         start_new_bblock = 1;
11771
11772                         if (*ip == CEE_LEAVE)
11773                                 ip += 5;
11774                         else
11775                                 ip += 2;
11776
11777                         break;
11778                 }
11779
11780                         /*
11781                          * Mono specific opcodes
11782                          */
11783                 case MONO_CUSTOM_PREFIX: {
11784
11785                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11786
11787                         CHECK_OPSIZE (2);
11788                         switch (ip [1]) {
11789                         case CEE_MONO_ICALL: {
11790                                 gpointer func;
11791                                 MonoJitICallInfo *info;
11792
11793                                 token = read32 (ip + 2);
11794                                 func = mono_method_get_wrapper_data (method, token);
11795                                 info = mono_find_jit_icall_by_addr (func);
11796                                 if (!info)
11797                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11798                                 g_assert (info);
11799
11800                                 CHECK_STACK (info->sig->param_count);
11801                                 sp -= info->sig->param_count;
11802
11803                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11804                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11805                                         *sp++ = ins;
11806
11807                                 ip += 6;
11808                                 inline_costs += 10 * num_calls++;
11809
11810                                 break;
11811                         }
11812                         case CEE_MONO_LDPTR_CARD_TABLE:
11813                         case CEE_MONO_LDPTR_NURSERY_START:
11814                         case CEE_MONO_LDPTR_NURSERY_BITS:
11815                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
11816                                 CHECK_STACK_OVF (1);
11817
11818                                 switch (ip [1]) {
11819                                         case CEE_MONO_LDPTR_CARD_TABLE:
11820                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
11821                                                 break;
11822                                         case CEE_MONO_LDPTR_NURSERY_START:
11823                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
11824                                                 break;
11825                                         case CEE_MONO_LDPTR_NURSERY_BITS:
11826                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
11827                                                 break;
11828                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
11829                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11830                                                 break;
11831                                 }
11832
11833                                 *sp++ = ins;
11834                                 ip += 2;
11835                                 inline_costs += 10 * num_calls++;
11836                                 break;
11837                         }
11838                         case CEE_MONO_LDPTR: {
11839                                 gpointer ptr;
11840
11841                                 CHECK_STACK_OVF (1);
11842                                 CHECK_OPSIZE (6);
11843                                 token = read32 (ip + 2);
11844
11845                                 ptr = mono_method_get_wrapper_data (method, token);
11846                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11847                                 *sp++ = ins;
11848                                 ip += 6;
11849                                 inline_costs += 10 * num_calls++;
11850                                 /* Can't embed random pointers into AOT code */
11851                                 DISABLE_AOT (cfg);
11852                                 break;
11853                         }
11854                         case CEE_MONO_JIT_ICALL_ADDR: {
11855                                 MonoJitICallInfo *callinfo;
11856                                 gpointer ptr;
11857
11858                                 CHECK_STACK_OVF (1);
11859                                 CHECK_OPSIZE (6);
11860                                 token = read32 (ip + 2);
11861
11862                                 ptr = mono_method_get_wrapper_data (method, token);
11863                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11864                                 g_assert (callinfo);
11865                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11866                                 *sp++ = ins;
11867                                 ip += 6;
11868                                 inline_costs += 10 * num_calls++;
11869                                 break;
11870                         }
11871                         case CEE_MONO_ICALL_ADDR: {
11872                                 MonoMethod *cmethod;
11873                                 gpointer ptr;
11874
11875                                 CHECK_STACK_OVF (1);
11876                                 CHECK_OPSIZE (6);
11877                                 token = read32 (ip + 2);
11878
11879                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
11880
11881                                 if (cfg->compile_aot) {
11882                                         if (cfg->direct_pinvoke && ip + 6 < end && (ip [6] == CEE_POP)) {
11883                                                 /*
11884                                                  * This is generated by emit_native_wrapper () to resolve the pinvoke address
11885                                                  * before the call, its not needed when using direct pinvoke.
11886                                                  * This is not an optimization, but its used to avoid looking up pinvokes
11887                                                  * on platforms which don't support dlopen ().
11888                                                  */
11889                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11890                                         } else {
11891                                                 EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11892                                         }
11893                                 } else {
11894                                         ptr = mono_lookup_internal_call (cmethod);
11895                                         g_assert (ptr);
11896                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11897                                 }
11898                                 *sp++ = ins;
11899                                 ip += 6;
11900                                 break;
11901                         }
11902                         case CEE_MONO_VTADDR: {
11903                                 MonoInst *src_var, *src;
11904
11905                                 CHECK_STACK (1);
11906                                 --sp;
11907
11908                                 // FIXME:
11909                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11910                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11911                                 *sp++ = src;
11912                                 ip += 2;
11913                                 break;
11914                         }
11915                         case CEE_MONO_NEWOBJ: {
11916                                 MonoInst *iargs [2];
11917
11918                                 CHECK_STACK_OVF (1);
11919                                 CHECK_OPSIZE (6);
11920                                 token = read32 (ip + 2);
11921                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11922                                 mono_class_init (klass);
11923                                 NEW_DOMAINCONST (cfg, iargs [0]);
11924                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11925                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11926                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11927                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
11928                                 ip += 6;
11929                                 inline_costs += 10 * num_calls++;
11930                                 break;
11931                         }
11932                         case CEE_MONO_OBJADDR:
11933                                 CHECK_STACK (1);
11934                                 --sp;
11935                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11936                                 ins->dreg = alloc_ireg_mp (cfg);
11937                                 ins->sreg1 = sp [0]->dreg;
11938                                 ins->type = STACK_MP;
11939                                 MONO_ADD_INS (cfg->cbb, ins);
11940                                 *sp++ = ins;
11941                                 ip += 2;
11942                                 break;
11943                         case CEE_MONO_LDNATIVEOBJ:
11944                                 /*
11945                                  * Similar to LDOBJ, but instead load the unmanaged 
11946                                  * representation of the vtype to the stack.
11947                                  */
11948                                 CHECK_STACK (1);
11949                                 CHECK_OPSIZE (6);
11950                                 --sp;
11951                                 token = read32 (ip + 2);
11952                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11953                                 g_assert (klass->valuetype);
11954                                 mono_class_init (klass);
11955
11956                                 {
11957                                         MonoInst *src, *dest, *temp;
11958
11959                                         src = sp [0];
11960                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11961                                         temp->backend.is_pinvoke = 1;
11962                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11963                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11964
11965                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11966                                         dest->type = STACK_VTYPE;
11967                                         dest->klass = klass;
11968
11969                                         *sp ++ = dest;
11970                                         ip += 6;
11971                                 }
11972                                 break;
11973                         case CEE_MONO_RETOBJ: {
11974                                 /*
11975                                  * Same as RET, but return the native representation of a vtype
11976                                  * to the caller.
11977                                  */
11978                                 g_assert (cfg->ret);
11979                                 g_assert (mono_method_signature (method)->pinvoke); 
11980                                 CHECK_STACK (1);
11981                                 --sp;
11982                                 
11983                                 CHECK_OPSIZE (6);
11984                                 token = read32 (ip + 2);    
11985                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11986
11987                                 if (!cfg->vret_addr) {
11988                                         g_assert (cfg->ret_var_is_local);
11989
11990                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11991                                 } else {
11992                                         EMIT_NEW_RETLOADA (cfg, ins);
11993                                 }
11994                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11995                                 
11996                                 if (sp != stack_start)
11997                                         UNVERIFIED;
11998                                 
11999                                 MONO_INST_NEW (cfg, ins, OP_BR);
12000                                 ins->inst_target_bb = end_bblock;
12001                                 MONO_ADD_INS (cfg->cbb, ins);
12002                                 link_bblock (cfg, cfg->cbb, end_bblock);
12003                                 start_new_bblock = 1;
12004                                 ip += 6;
12005                                 break;
12006                         }
12007                         case CEE_MONO_SAVE_LMF:
12008                         case CEE_MONO_RESTORE_LMF:
12009                                 ip += 2;
12010                                 break;
12011                         case CEE_MONO_CLASSCONST:
12012                                 CHECK_STACK_OVF (1);
12013                                 CHECK_OPSIZE (6);
12014                                 token = read32 (ip + 2);
12015                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12016                                 *sp++ = ins;
12017                                 ip += 6;
12018                                 inline_costs += 10 * num_calls++;
12019                                 break;
12020                         case CEE_MONO_NOT_TAKEN:
12021                                 cfg->cbb->out_of_line = TRUE;
12022                                 ip += 2;
12023                                 break;
12024                         case CEE_MONO_TLS: {
12025                                 MonoTlsKey key;
12026
12027                                 CHECK_STACK_OVF (1);
12028                                 CHECK_OPSIZE (6);
12029                                 key = (MonoTlsKey)read32 (ip + 2);
12030                                 g_assert (key < TLS_KEY_NUM);
12031
12032                                 ins = mono_create_tls_get (cfg, key);
12033                                 g_assert (ins);
12034                                 ins->type = STACK_PTR;
12035                                 *sp++ = ins;
12036                                 ip += 6;
12037                                 break;
12038                         }
12039                         case CEE_MONO_DYN_CALL: {
12040                                 MonoCallInst *call;
12041
12042                                 /* It would be easier to call a trampoline, but that would put an
12043                                  * extra frame on the stack, confusing exception handling. So
12044                                  * implement it inline using an opcode for now.
12045                                  */
12046
12047                                 if (!cfg->dyn_call_var) {
12048                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12049                                         /* prevent it from being register allocated */
12050                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12051                                 }
12052
12053                                 /* Has to use a call inst since it local regalloc expects it */
12054                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12055                                 ins = (MonoInst*)call;
12056                                 sp -= 2;
12057                                 ins->sreg1 = sp [0]->dreg;
12058                                 ins->sreg2 = sp [1]->dreg;
12059                                 MONO_ADD_INS (cfg->cbb, ins);
12060
12061                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12062
12063                                 ip += 2;
12064                                 inline_costs += 10 * num_calls++;
12065
12066                                 break;
12067                         }
12068                         case CEE_MONO_MEMORY_BARRIER: {
12069                                 CHECK_OPSIZE (6);
12070                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12071                                 ip += 6;
12072                                 break;
12073                         }
12074                         case CEE_MONO_ATOMIC_STORE_I4: {
12075                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
12076
12077                                 CHECK_OPSIZE (6);
12078                                 CHECK_STACK (2);
12079                                 sp -= 2;
12080
12081                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
12082                                 ins->dreg = sp [0]->dreg;
12083                                 ins->sreg1 = sp [1]->dreg;
12084                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
12085                                 MONO_ADD_INS (cfg->cbb, ins);
12086
12087                                 ip += 6;
12088                                 break;
12089                         }
12090                         case CEE_MONO_JIT_ATTACH: {
12091                                 MonoInst *args [16], *domain_ins;
12092                                 MonoInst *ad_ins, *jit_tls_ins;
12093                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12094
12095                                 g_assert (!mono_threads_is_coop_enabled ());
12096
12097                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12098
12099                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12100                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12101
12102                                 ad_ins = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
12103                                 jit_tls_ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
12104
12105                                 if (ad_ins && jit_tls_ins) {
12106                                         NEW_BBLOCK (cfg, next_bb);
12107                                         NEW_BBLOCK (cfg, call_bb);
12108
12109                                         if (cfg->compile_aot) {
12110                                                 /* AOT code is only used in the root domain */
12111                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12112                                         } else {
12113                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12114                                         }
12115                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12116                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12117
12118                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12119                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12120
12121                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12122                                         MONO_START_BB (cfg, call_bb);
12123                                 }
12124
12125                                 /* AOT code is only used in the root domain */
12126                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12127                                 if (cfg->compile_aot) {
12128                                         MonoInst *addr;
12129
12130                                         /*
12131                                          * This is called on unattached threads, so it cannot go through the trampoline
12132                                          * infrastructure. Use an indirect call through a got slot initialized at load time
12133                                          * instead.
12134                                          */
12135                                         EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_JIT_THREAD_ATTACH, NULL);
12136                                         ins = mono_emit_calli (cfg, helper_sig_jit_thread_attach, args, addr, NULL, NULL);
12137                                 } else {
12138                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12139                                 }
12140                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12141
12142                                 if (next_bb)
12143                                         MONO_START_BB (cfg, next_bb);
12144
12145                                 ip += 2;
12146                                 break;
12147                         }
12148                         case CEE_MONO_JIT_DETACH: {
12149                                 MonoInst *args [16];
12150
12151                                 /* Restore the original domain */
12152                                 dreg = alloc_ireg (cfg);
12153                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12154                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12155                                 ip += 2;
12156                                 break;
12157                         }
12158                         case CEE_MONO_CALLI_EXTRA_ARG: {
12159                                 MonoInst *addr;
12160                                 MonoMethodSignature *fsig;
12161                                 MonoInst *arg;
12162
12163                                 /*
12164                                  * This is the same as CEE_CALLI, but passes an additional argument
12165                                  * to the called method in llvmonly mode.
12166                                  * This is only used by delegate invoke wrappers to call the
12167                                  * actual delegate method.
12168                                  */
12169                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12170
12171                                 CHECK_OPSIZE (6);
12172                                 token = read32 (ip + 2);
12173
12174                                 ins = NULL;
12175
12176                                 cmethod = NULL;
12177                                 CHECK_STACK (1);
12178                                 --sp;
12179                                 addr = *sp;
12180                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12181                                 CHECK_CFG_ERROR;
12182
12183                                 if (cfg->llvm_only)
12184                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12185
12186                                 n = fsig->param_count + fsig->hasthis + 1;
12187
12188                                 CHECK_STACK (n);
12189
12190                                 sp -= n;
12191                                 arg = sp [n - 1];
12192
12193                                 if (cfg->llvm_only) {
12194                                         /*
12195                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12196                                          * cconv. This is set by mono_init_delegate ().
12197                                          */
12198                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12199                                                 MonoInst *callee = addr;
12200                                                 MonoInst *call, *localloc_ins;
12201                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12202                                                 int low_bit_reg = alloc_preg (cfg);
12203
12204                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12205                                                 NEW_BBLOCK (cfg, end_bb);
12206
12207                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12208                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12209                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12210
12211                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12212                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12213                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12214                                                 /*
12215                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12216                                                  */
12217                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12218                                                 ins->dreg = alloc_preg (cfg);
12219                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12220                                                 MONO_ADD_INS (cfg->cbb, ins);
12221                                                 localloc_ins = ins;
12222                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12223                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12224                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12225
12226                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12227                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12228
12229                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12230                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12231                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12232                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12233                                                 ins->dreg = call->dreg;
12234
12235                                                 MONO_START_BB (cfg, end_bb);
12236                                         } else {
12237                                                 /* Caller uses a normal calling conv */
12238
12239                                                 MonoInst *callee = addr;
12240                                                 MonoInst *call, *localloc_ins;
12241                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12242                                                 int low_bit_reg = alloc_preg (cfg);
12243
12244                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12245                                                 NEW_BBLOCK (cfg, end_bb);
12246
12247                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12248                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12249                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12250
12251                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12252                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12253                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12254                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12255                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12256                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12257                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12258                                                 MONO_ADD_INS (cfg->cbb, addr);
12259                                                 /*
12260                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12261                                                  */
12262                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12263                                                 ins->dreg = alloc_preg (cfg);
12264                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12265                                                 MONO_ADD_INS (cfg->cbb, ins);
12266                                                 localloc_ins = ins;
12267                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12268                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12269                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12270
12271                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12272                                                 ins->dreg = call->dreg;
12273                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12274
12275                                                 MONO_START_BB (cfg, end_bb);
12276                                         }
12277                                 } else {
12278                                         /* Same as CEE_CALLI */
12279                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12280                                                 /*
12281                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12282                                                  */
12283                                                 MonoInst *callee = addr;
12284
12285                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12286                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12287                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12288                                         } else {
12289                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12290                                         }
12291                                 }
12292
12293                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12294                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12295
12296                                 CHECK_CFG_EXCEPTION;
12297
12298                                 ip += 6;
12299                                 ins_flag = 0;
12300                                 constrained_class = NULL;
12301                                 break;
12302                         }
12303                         case CEE_MONO_LDDOMAIN:
12304                                 CHECK_STACK_OVF (1);
12305                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
12306                                 ip += 2;
12307                                 *sp++ = ins;
12308                                 break;
12309                         case CEE_MONO_GET_LAST_ERROR:
12310                                 CHECK_OPSIZE (2);
12311                                 CHECK_STACK_OVF (1);
12312
12313                                 MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
12314                                 ins->dreg = alloc_dreg (cfg, STACK_I4);
12315                                 ins->type = STACK_I4;
12316                                 MONO_ADD_INS (cfg->cbb, ins);
12317
12318                                 ip += 2;
12319                                 *sp++ = ins;
12320                                 break;
12321                         default:
12322                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12323                                 break;
12324                         }
12325                         break;
12326                 }
12327
12328                 case CEE_PREFIX1: {
12329                         CHECK_OPSIZE (2);
12330                         switch (ip [1]) {
12331                         case CEE_ARGLIST: {
12332                                 /* somewhat similar to LDTOKEN */
12333                                 MonoInst *addr, *vtvar;
12334                                 CHECK_STACK_OVF (1);
12335                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12336
12337                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12338                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12339
12340                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12341                                 ins->type = STACK_VTYPE;
12342                                 ins->klass = mono_defaults.argumenthandle_class;
12343                                 *sp++ = ins;
12344                                 ip += 2;
12345                                 break;
12346                         }
12347                         case CEE_CEQ:
12348                         case CEE_CGT:
12349                         case CEE_CGT_UN:
12350                         case CEE_CLT:
12351                         case CEE_CLT_UN: {
12352                                 MonoInst *cmp, *arg1, *arg2;
12353
12354                                 CHECK_STACK (2);
12355                                 sp -= 2;
12356                                 arg1 = sp [0];
12357                                 arg2 = sp [1];
12358
12359                                 /*
12360                                  * The following transforms:
12361                                  *    CEE_CEQ    into OP_CEQ
12362                                  *    CEE_CGT    into OP_CGT
12363                                  *    CEE_CGT_UN into OP_CGT_UN
12364                                  *    CEE_CLT    into OP_CLT
12365                                  *    CEE_CLT_UN into OP_CLT_UN
12366                                  */
12367                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12368
12369                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12370                                 cmp->sreg1 = arg1->dreg;
12371                                 cmp->sreg2 = arg2->dreg;
12372                                 type_from_op (cfg, cmp, arg1, arg2);
12373                                 CHECK_TYPE (cmp);
12374                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12375                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12376                                         cmp->opcode = OP_LCOMPARE;
12377                                 else if (arg1->type == STACK_R4)
12378                                         cmp->opcode = OP_RCOMPARE;
12379                                 else if (arg1->type == STACK_R8)
12380                                         cmp->opcode = OP_FCOMPARE;
12381                                 else
12382                                         cmp->opcode = OP_ICOMPARE;
12383                                 MONO_ADD_INS (cfg->cbb, cmp);
12384                                 ins->type = STACK_I4;
12385                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
12386                                 type_from_op (cfg, ins, arg1, arg2);
12387
12388                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12389                                         /*
12390                                          * The backends expect the fceq opcodes to do the
12391                                          * comparison too.
12392                                          */
12393                                         ins->sreg1 = cmp->sreg1;
12394                                         ins->sreg2 = cmp->sreg2;
12395                                         NULLIFY_INS (cmp);
12396                                 }
12397                                 MONO_ADD_INS (cfg->cbb, ins);
12398                                 *sp++ = ins;
12399                                 ip += 2;
12400                                 break;
12401                         }
12402                         case CEE_LDFTN: {
12403                                 MonoInst *argconst;
12404                                 MonoMethod *cil_method;
12405
12406                                 CHECK_STACK_OVF (1);
12407                                 CHECK_OPSIZE (6);
12408                                 n = read32 (ip + 2);
12409                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12410                                 CHECK_CFG_ERROR;
12411
12412                                 mono_class_init (cmethod->klass);
12413
12414                                 mono_save_token_info (cfg, image, n, cmethod);
12415
12416                                 context_used = mini_method_check_context_used (cfg, cmethod);
12417
12418                                 cil_method = cmethod;
12419                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12420                                         emit_method_access_failure (cfg, method, cil_method);
12421
12422                                 if (mono_security_core_clr_enabled ())
12423                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12424
12425                                 /* 
12426                                  * Optimize the common case of ldftn+delegate creation
12427                                  */
12428                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12429                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12430                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12431                                                 MonoInst *target_ins, *handle_ins;
12432                                                 MonoMethod *invoke;
12433                                                 int invoke_context_used;
12434
12435                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12436                                                 if (!invoke || !mono_method_signature (invoke))
12437                                                         LOAD_ERROR;
12438
12439                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12440
12441                                                 target_ins = sp [-1];
12442
12443                                                 if (mono_security_core_clr_enabled ())
12444                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12445
12446                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12447                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12448                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12449                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12450                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12451                                                         }
12452                                                 }
12453
12454                                                 /* FIXME: SGEN support */
12455                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12456                                                         ip += 6;
12457                                                         if (cfg->verbose_level > 3)
12458                                                                 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));
12459                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12460                                                                 sp --;
12461                                                                 *sp = handle_ins;
12462                                                                 CHECK_CFG_EXCEPTION;
12463                                                                 ip += 5;
12464                                                                 sp ++;
12465                                                                 break;
12466                                                         }
12467                                                         ip -= 6;
12468                                                 }
12469                                         }
12470                                 }
12471
12472                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12473                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12474                                 *sp++ = ins;
12475                                 
12476                                 ip += 6;
12477                                 inline_costs += 10 * num_calls++;
12478                                 break;
12479                         }
12480                         case CEE_LDVIRTFTN: {
12481                                 MonoInst *args [2];
12482
12483                                 CHECK_STACK (1);
12484                                 CHECK_OPSIZE (6);
12485                                 n = read32 (ip + 2);
12486                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12487                                 CHECK_CFG_ERROR;
12488
12489                                 mono_class_init (cmethod->klass);
12490  
12491                                 context_used = mini_method_check_context_used (cfg, cmethod);
12492
12493                                 if (mono_security_core_clr_enabled ())
12494                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12495
12496                                 /*
12497                                  * Optimize the common case of ldvirtftn+delegate creation
12498                                  */
12499                                 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)) {
12500                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12501                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12502                                                 MonoInst *target_ins, *handle_ins;
12503                                                 MonoMethod *invoke;
12504                                                 int invoke_context_used;
12505                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12506
12507                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12508                                                 if (!invoke || !mono_method_signature (invoke))
12509                                                         LOAD_ERROR;
12510
12511                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12512
12513                                                 target_ins = sp [-1];
12514
12515                                                 if (mono_security_core_clr_enabled ())
12516                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12517
12518                                                 /* FIXME: SGEN support */
12519                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12520                                                         ip += 6;
12521                                                         if (cfg->verbose_level > 3)
12522                                                                 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));
12523                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12524                                                                 sp -= 2;
12525                                                                 *sp = handle_ins;
12526                                                                 CHECK_CFG_EXCEPTION;
12527                                                                 ip += 5;
12528                                                                 sp ++;
12529                                                                 break;
12530                                                         }
12531                                                         ip -= 6;
12532                                                 }
12533                                         }
12534                                 }
12535
12536                                 --sp;
12537                                 args [0] = *sp;
12538
12539                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12540                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12541
12542                                 if (context_used)
12543                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12544                                 else
12545                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12546
12547                                 ip += 6;
12548                                 inline_costs += 10 * num_calls++;
12549                                 break;
12550                         }
12551                         case CEE_LDARG:
12552                                 CHECK_STACK_OVF (1);
12553                                 CHECK_OPSIZE (4);
12554                                 n = read16 (ip + 2);
12555                                 CHECK_ARG (n);
12556                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12557                                 *sp++ = ins;
12558                                 ip += 4;
12559                                 break;
12560                         case CEE_LDARGA:
12561                                 CHECK_STACK_OVF (1);
12562                                 CHECK_OPSIZE (4);
12563                                 n = read16 (ip + 2);
12564                                 CHECK_ARG (n);
12565                                 NEW_ARGLOADA (cfg, ins, n);
12566                                 MONO_ADD_INS (cfg->cbb, ins);
12567                                 *sp++ = ins;
12568                                 ip += 4;
12569                                 break;
12570                         case CEE_STARG:
12571                                 CHECK_STACK (1);
12572                                 --sp;
12573                                 CHECK_OPSIZE (4);
12574                                 n = read16 (ip + 2);
12575                                 CHECK_ARG (n);
12576                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12577                                         UNVERIFIED;
12578                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12579                                 ip += 4;
12580                                 break;
12581                         case CEE_LDLOC:
12582                                 CHECK_STACK_OVF (1);
12583                                 CHECK_OPSIZE (4);
12584                                 n = read16 (ip + 2);
12585                                 CHECK_LOCAL (n);
12586                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12587                                 *sp++ = ins;
12588                                 ip += 4;
12589                                 break;
12590                         case CEE_LDLOCA: {
12591                                 unsigned char *tmp_ip;
12592                                 CHECK_STACK_OVF (1);
12593                                 CHECK_OPSIZE (4);
12594                                 n = read16 (ip + 2);
12595                                 CHECK_LOCAL (n);
12596
12597                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12598                                         ip = tmp_ip;
12599                                         inline_costs += 1;
12600                                         break;
12601                                 }                       
12602                                 
12603                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12604                                 *sp++ = ins;
12605                                 ip += 4;
12606                                 break;
12607                         }
12608                         case CEE_STLOC:
12609                                 CHECK_STACK (1);
12610                                 --sp;
12611                                 CHECK_OPSIZE (4);
12612                                 n = read16 (ip + 2);
12613                                 CHECK_LOCAL (n);
12614                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12615                                         UNVERIFIED;
12616                                 emit_stloc_ir (cfg, sp, header, n);
12617                                 ip += 4;
12618                                 inline_costs += 1;
12619                                 break;
12620                         case CEE_LOCALLOC: {
12621                                 CHECK_STACK (1);
12622                                 MonoBasicBlock *non_zero_bb, *end_bb;
12623                                 int alloc_ptr = alloc_preg (cfg);
12624                                 --sp;
12625                                 if (sp != stack_start) 
12626                                         UNVERIFIED;
12627                                 if (cfg->method != method) 
12628                                         /* 
12629                                          * Inlining this into a loop in a parent could lead to 
12630                                          * stack overflows which is different behavior than the
12631                                          * non-inlined case, thus disable inlining in this case.
12632                                          */
12633                                         INLINE_FAILURE("localloc");
12634
12635                                 NEW_BBLOCK (cfg, non_zero_bb);
12636                                 NEW_BBLOCK (cfg, end_bb);
12637
12638                                 /* if size != zero */
12639                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
12640                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
12641
12642                                 //size is zero, so result is NULL
12643                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
12644                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12645
12646                                 MONO_START_BB (cfg, non_zero_bb);
12647                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12648                                 ins->dreg = alloc_ptr;
12649                                 ins->sreg1 = sp [0]->dreg;
12650                                 ins->type = STACK_PTR;
12651                                 MONO_ADD_INS (cfg->cbb, ins);
12652
12653                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12654                                 if (init_locals)
12655                                         ins->flags |= MONO_INST_INIT;
12656
12657                                 MONO_START_BB (cfg, end_bb);
12658                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
12659                                 ins->type = STACK_PTR;
12660
12661                                 *sp++ = ins;
12662                                 ip += 2;
12663                                 break;
12664                         }
12665                         case CEE_ENDFILTER: {
12666                                 MonoExceptionClause *clause, *nearest;
12667                                 int cc;
12668
12669                                 CHECK_STACK (1);
12670                                 --sp;
12671                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12672                                         UNVERIFIED;
12673                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12674                                 ins->sreg1 = (*sp)->dreg;
12675                                 MONO_ADD_INS (cfg->cbb, ins);
12676                                 start_new_bblock = 1;
12677                                 ip += 2;
12678
12679                                 nearest = NULL;
12680                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12681                                         clause = &header->clauses [cc];
12682                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12683                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12684                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12685                                                 nearest = clause;
12686                                 }
12687                                 g_assert (nearest);
12688                                 if ((ip - header->code) != nearest->handler_offset)
12689                                         UNVERIFIED;
12690
12691                                 break;
12692                         }
12693                         case CEE_UNALIGNED_:
12694                                 ins_flag |= MONO_INST_UNALIGNED;
12695                                 /* FIXME: record alignment? we can assume 1 for now */
12696                                 CHECK_OPSIZE (3);
12697                                 ip += 3;
12698                                 break;
12699                         case CEE_VOLATILE_:
12700                                 ins_flag |= MONO_INST_VOLATILE;
12701                                 ip += 2;
12702                                 break;
12703                         case CEE_TAIL_:
12704                                 ins_flag   |= MONO_INST_TAILCALL;
12705                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12706                                 /* Can't inline tail calls at this time */
12707                                 inline_costs += 100000;
12708                                 ip += 2;
12709                                 break;
12710                         case CEE_INITOBJ:
12711                                 CHECK_STACK (1);
12712                                 --sp;
12713                                 CHECK_OPSIZE (6);
12714                                 token = read32 (ip + 2);
12715                                 klass = mini_get_class (method, token, generic_context);
12716                                 CHECK_TYPELOAD (klass);
12717                                 if (generic_class_is_reference_type (cfg, klass))
12718                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12719                                 else
12720                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12721                                 ip += 6;
12722                                 inline_costs += 1;
12723                                 break;
12724                         case CEE_CONSTRAINED_:
12725                                 CHECK_OPSIZE (6);
12726                                 token = read32 (ip + 2);
12727                                 constrained_class = mini_get_class (method, token, generic_context);
12728                                 CHECK_TYPELOAD (constrained_class);
12729                                 ip += 6;
12730                                 break;
12731                         case CEE_CPBLK:
12732                         case CEE_INITBLK: {
12733                                 MonoInst *iargs [3];
12734                                 CHECK_STACK (3);
12735                                 sp -= 3;
12736
12737                                 /* Skip optimized paths for volatile operations. */
12738                                 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)) {
12739                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12740                                 } 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)) {
12741                                         /* emit_memset only works when val == 0 */
12742                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12743                                 } else {
12744                                         MonoInst *call;
12745                                         iargs [0] = sp [0];
12746                                         iargs [1] = sp [1];
12747                                         iargs [2] = sp [2];
12748                                         if (ip [1] == CEE_CPBLK) {
12749                                                 /*
12750                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12751                                                  * and release barriers for cpblk. It is technically both a load and
12752                                                  * store operation, so it seems like that's the sensible thing to do.
12753                                                  *
12754                                                  * FIXME: We emit full barriers on both sides of the operation for
12755                                                  * simplicity. We should have a separate atomic memcpy method instead.
12756                                                  */
12757                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12758
12759                                                 if (ins_flag & MONO_INST_VOLATILE)
12760                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12761
12762                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12763                                                 call->flags |= ins_flag;
12764
12765                                                 if (ins_flag & MONO_INST_VOLATILE)
12766                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12767                                         } else {
12768                                                 MonoMethod *memset_method = get_memset_method ();
12769                                                 if (ins_flag & MONO_INST_VOLATILE) {
12770                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12771                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12772                                                 }
12773                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12774                                                 call->flags |= ins_flag;
12775                                         }
12776                                 }
12777                                 ip += 2;
12778                                 ins_flag = 0;
12779                                 inline_costs += 1;
12780                                 break;
12781                         }
12782                         case CEE_NO_:
12783                                 CHECK_OPSIZE (3);
12784                                 if (ip [2] & 0x1)
12785                                         ins_flag |= MONO_INST_NOTYPECHECK;
12786                                 if (ip [2] & 0x2)
12787                                         ins_flag |= MONO_INST_NORANGECHECK;
12788                                 /* we ignore the no-nullcheck for now since we
12789                                  * really do it explicitly only when doing callvirt->call
12790                                  */
12791                                 ip += 3;
12792                                 break;
12793                         case CEE_RETHROW: {
12794                                 MonoInst *load;
12795                                 int handler_offset = -1;
12796
12797                                 for (i = 0; i < header->num_clauses; ++i) {
12798                                         MonoExceptionClause *clause = &header->clauses [i];
12799                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12800                                                 handler_offset = clause->handler_offset;
12801                                                 break;
12802                                         }
12803                                 }
12804
12805                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12806
12807                                 if (handler_offset == -1)
12808                                         UNVERIFIED;
12809
12810                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12811                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12812                                 ins->sreg1 = load->dreg;
12813                                 MONO_ADD_INS (cfg->cbb, ins);
12814
12815                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12816                                 MONO_ADD_INS (cfg->cbb, ins);
12817
12818                                 sp = stack_start;
12819                                 link_bblock (cfg, cfg->cbb, end_bblock);
12820                                 start_new_bblock = 1;
12821                                 ip += 2;
12822                                 break;
12823                         }
12824                         case CEE_SIZEOF: {
12825                                 guint32 val;
12826                                 int ialign;
12827
12828                                 CHECK_STACK_OVF (1);
12829                                 CHECK_OPSIZE (6);
12830                                 token = read32 (ip + 2);
12831                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12832                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12833                                         CHECK_CFG_ERROR;
12834
12835                                         val = mono_type_size (type, &ialign);
12836                                 } else {
12837                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12838                                         CHECK_TYPELOAD (klass);
12839
12840                                         val = mono_type_size (&klass->byval_arg, &ialign);
12841
12842                                         if (mini_is_gsharedvt_klass (klass))
12843                                                 GSHAREDVT_FAILURE (*ip);
12844                                 }
12845                                 EMIT_NEW_ICONST (cfg, ins, val);
12846                                 *sp++= ins;
12847                                 ip += 6;
12848                                 break;
12849                         }
12850                         case CEE_REFANYTYPE: {
12851                                 MonoInst *src_var, *src;
12852
12853                                 GSHAREDVT_FAILURE (*ip);
12854
12855                                 CHECK_STACK (1);
12856                                 --sp;
12857
12858                                 // FIXME:
12859                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12860                                 if (!src_var)
12861                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12862                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12863                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12864                                 *sp++ = ins;
12865                                 ip += 2;
12866                                 break;
12867                         }
12868                         case CEE_READONLY_:
12869                                 readonly = TRUE;
12870                                 ip += 2;
12871                                 break;
12872
12873                         case CEE_UNUSED56:
12874                         case CEE_UNUSED57:
12875                         case CEE_UNUSED70:
12876                         case CEE_UNUSED:
12877                         case CEE_UNUSED99:
12878                                 UNVERIFIED;
12879                                 
12880                         default:
12881                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12882                                 UNVERIFIED;
12883                         }
12884                         break;
12885                 }
12886                 case CEE_UNUSED58:
12887                 case CEE_UNUSED1:
12888                         UNVERIFIED;
12889
12890                 default:
12891                         g_warning ("opcode 0x%02x not handled", *ip);
12892                         UNVERIFIED;
12893                 }
12894         }
12895         if (start_new_bblock != 1)
12896                 UNVERIFIED;
12897
12898         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
12899         if (cfg->cbb->next_bb) {
12900                 /* This could already be set because of inlining, #693905 */
12901                 MonoBasicBlock *bb = cfg->cbb;
12902
12903                 while (bb->next_bb)
12904                         bb = bb->next_bb;
12905                 bb->next_bb = end_bblock;
12906         } else {
12907                 cfg->cbb->next_bb = end_bblock;
12908         }
12909
12910         if (cfg->method == method && cfg->domainvar) {
12911                 MonoInst *store;
12912                 MonoInst *get_domain;
12913
12914                 cfg->cbb = init_localsbb;
12915
12916                 get_domain = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
12917                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12918                 MONO_ADD_INS (cfg->cbb, store);
12919         }
12920
12921 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12922         if (cfg->compile_aot)
12923                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12924                 mono_get_got_var (cfg);
12925 #endif
12926
12927         if (cfg->method == method && cfg->got_var)
12928                 mono_emit_load_got_addr (cfg);
12929
12930         if (init_localsbb) {
12931                 cfg->cbb = init_localsbb;
12932                 cfg->ip = NULL;
12933                 for (i = 0; i < header->num_locals; ++i) {
12934                         emit_init_local (cfg, i, header->locals [i], init_locals);
12935                 }
12936         }
12937
12938         if (cfg->init_ref_vars && cfg->method == method) {
12939                 /* Emit initialization for ref vars */
12940                 // FIXME: Avoid duplication initialization for IL locals.
12941                 for (i = 0; i < cfg->num_varinfo; ++i) {
12942                         MonoInst *ins = cfg->varinfo [i];
12943
12944                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12945                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12946                 }
12947         }
12948
12949         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
12950                 cfg->cbb = init_localsbb;
12951                 emit_push_lmf (cfg);
12952         }
12953
12954         cfg->cbb = init_localsbb;
12955         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12956
12957         if (seq_points) {
12958                 MonoBasicBlock *bb;
12959
12960                 /*
12961                  * Make seq points at backward branch targets interruptable.
12962                  */
12963                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12964                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12965                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12966         }
12967
12968         /* Add a sequence point for method entry/exit events */
12969         if (seq_points && cfg->gen_sdb_seq_points) {
12970                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12971                 MONO_ADD_INS (init_localsbb, ins);
12972                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12973                 MONO_ADD_INS (cfg->bb_exit, ins);
12974         }
12975
12976         /*
12977          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12978          * the code they refer to was dead (#11880).
12979          */
12980         if (sym_seq_points) {
12981                 for (i = 0; i < header->code_size; ++i) {
12982                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12983                                 MonoInst *ins;
12984
12985                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12986                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12987                         }
12988                 }
12989         }
12990
12991         cfg->ip = NULL;
12992
12993         if (cfg->method == method) {
12994                 MonoBasicBlock *bb;
12995                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12996                         if (bb == cfg->bb_init)
12997                                 bb->region = -1;
12998                         else
12999                                 bb->region = mono_find_block_region (cfg, bb->real_offset);
13000                         if (cfg->spvars)
13001                                 mono_create_spvar_for_region (cfg, bb->region);
13002                         if (cfg->verbose_level > 2)
13003                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13004                 }
13005         } else {
13006                 MonoBasicBlock *bb;
13007                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
13008                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
13009                         bb->real_offset = inline_offset;
13010                 }
13011         }
13012
13013         if (inline_costs < 0) {
13014                 char *mname;
13015
13016                 /* Method is too large */
13017                 mname = mono_method_full_name (method, TRUE);
13018                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13019                 g_free (mname);
13020         }
13021
13022         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13023                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13024
13025         goto cleanup;
13026
13027 mono_error_exit:
13028         g_assert (!mono_error_ok (&cfg->error));
13029         goto cleanup;
13030  
13031  exception_exit:
13032         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13033         goto cleanup;
13034
13035  unverified:
13036         set_exception_type_from_invalid_il (cfg, method, ip);
13037         goto cleanup;
13038
13039  cleanup:
13040         g_slist_free (class_inits);
13041         mono_basic_block_free (original_bb);
13042         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13043         if (cfg->exception_type)
13044                 return -1;
13045         else
13046                 return inline_costs;
13047 }
13048
13049 static int
13050 store_membase_reg_to_store_membase_imm (int opcode)
13051 {
13052         switch (opcode) {
13053         case OP_STORE_MEMBASE_REG:
13054                 return OP_STORE_MEMBASE_IMM;
13055         case OP_STOREI1_MEMBASE_REG:
13056                 return OP_STOREI1_MEMBASE_IMM;
13057         case OP_STOREI2_MEMBASE_REG:
13058                 return OP_STOREI2_MEMBASE_IMM;
13059         case OP_STOREI4_MEMBASE_REG:
13060                 return OP_STOREI4_MEMBASE_IMM;
13061         case OP_STOREI8_MEMBASE_REG:
13062                 return OP_STOREI8_MEMBASE_IMM;
13063         default:
13064                 g_assert_not_reached ();
13065         }
13066
13067         return -1;
13068 }               
13069
13070 int
13071 mono_op_to_op_imm (int opcode)
13072 {
13073         switch (opcode) {
13074         case OP_IADD:
13075                 return OP_IADD_IMM;
13076         case OP_ISUB:
13077                 return OP_ISUB_IMM;
13078         case OP_IDIV:
13079                 return OP_IDIV_IMM;
13080         case OP_IDIV_UN:
13081                 return OP_IDIV_UN_IMM;
13082         case OP_IREM:
13083                 return OP_IREM_IMM;
13084         case OP_IREM_UN:
13085                 return OP_IREM_UN_IMM;
13086         case OP_IMUL:
13087                 return OP_IMUL_IMM;
13088         case OP_IAND:
13089                 return OP_IAND_IMM;
13090         case OP_IOR:
13091                 return OP_IOR_IMM;
13092         case OP_IXOR:
13093                 return OP_IXOR_IMM;
13094         case OP_ISHL:
13095                 return OP_ISHL_IMM;
13096         case OP_ISHR:
13097                 return OP_ISHR_IMM;
13098         case OP_ISHR_UN:
13099                 return OP_ISHR_UN_IMM;
13100
13101         case OP_LADD:
13102                 return OP_LADD_IMM;
13103         case OP_LSUB:
13104                 return OP_LSUB_IMM;
13105         case OP_LAND:
13106                 return OP_LAND_IMM;
13107         case OP_LOR:
13108                 return OP_LOR_IMM;
13109         case OP_LXOR:
13110                 return OP_LXOR_IMM;
13111         case OP_LSHL:
13112                 return OP_LSHL_IMM;
13113         case OP_LSHR:
13114                 return OP_LSHR_IMM;
13115         case OP_LSHR_UN:
13116                 return OP_LSHR_UN_IMM;
13117 #if SIZEOF_REGISTER == 8
13118         case OP_LREM:
13119                 return OP_LREM_IMM;
13120 #endif
13121
13122         case OP_COMPARE:
13123                 return OP_COMPARE_IMM;
13124         case OP_ICOMPARE:
13125                 return OP_ICOMPARE_IMM;
13126         case OP_LCOMPARE:
13127                 return OP_LCOMPARE_IMM;
13128
13129         case OP_STORE_MEMBASE_REG:
13130                 return OP_STORE_MEMBASE_IMM;
13131         case OP_STOREI1_MEMBASE_REG:
13132                 return OP_STOREI1_MEMBASE_IMM;
13133         case OP_STOREI2_MEMBASE_REG:
13134                 return OP_STOREI2_MEMBASE_IMM;
13135         case OP_STOREI4_MEMBASE_REG:
13136                 return OP_STOREI4_MEMBASE_IMM;
13137
13138 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13139         case OP_X86_PUSH:
13140                 return OP_X86_PUSH_IMM;
13141         case OP_X86_COMPARE_MEMBASE_REG:
13142                 return OP_X86_COMPARE_MEMBASE_IMM;
13143 #endif
13144 #if defined(TARGET_AMD64)
13145         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13146                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13147 #endif
13148         case OP_VOIDCALL_REG:
13149                 return OP_VOIDCALL;
13150         case OP_CALL_REG:
13151                 return OP_CALL;
13152         case OP_LCALL_REG:
13153                 return OP_LCALL;
13154         case OP_FCALL_REG:
13155                 return OP_FCALL;
13156         case OP_LOCALLOC:
13157                 return OP_LOCALLOC_IMM;
13158         }
13159
13160         return -1;
13161 }
13162
13163 static int
13164 ldind_to_load_membase (int opcode)
13165 {
13166         switch (opcode) {
13167         case CEE_LDIND_I1:
13168                 return OP_LOADI1_MEMBASE;
13169         case CEE_LDIND_U1:
13170                 return OP_LOADU1_MEMBASE;
13171         case CEE_LDIND_I2:
13172                 return OP_LOADI2_MEMBASE;
13173         case CEE_LDIND_U2:
13174                 return OP_LOADU2_MEMBASE;
13175         case CEE_LDIND_I4:
13176                 return OP_LOADI4_MEMBASE;
13177         case CEE_LDIND_U4:
13178                 return OP_LOADU4_MEMBASE;
13179         case CEE_LDIND_I:
13180                 return OP_LOAD_MEMBASE;
13181         case CEE_LDIND_REF:
13182                 return OP_LOAD_MEMBASE;
13183         case CEE_LDIND_I8:
13184                 return OP_LOADI8_MEMBASE;
13185         case CEE_LDIND_R4:
13186                 return OP_LOADR4_MEMBASE;
13187         case CEE_LDIND_R8:
13188                 return OP_LOADR8_MEMBASE;
13189         default:
13190                 g_assert_not_reached ();
13191         }
13192
13193         return -1;
13194 }
13195
13196 static int
13197 stind_to_store_membase (int opcode)
13198 {
13199         switch (opcode) {
13200         case CEE_STIND_I1:
13201                 return OP_STOREI1_MEMBASE_REG;
13202         case CEE_STIND_I2:
13203                 return OP_STOREI2_MEMBASE_REG;
13204         case CEE_STIND_I4:
13205                 return OP_STOREI4_MEMBASE_REG;
13206         case CEE_STIND_I:
13207         case CEE_STIND_REF:
13208                 return OP_STORE_MEMBASE_REG;
13209         case CEE_STIND_I8:
13210                 return OP_STOREI8_MEMBASE_REG;
13211         case CEE_STIND_R4:
13212                 return OP_STORER4_MEMBASE_REG;
13213         case CEE_STIND_R8:
13214                 return OP_STORER8_MEMBASE_REG;
13215         default:
13216                 g_assert_not_reached ();
13217         }
13218
13219         return -1;
13220 }
13221
13222 int
13223 mono_load_membase_to_load_mem (int opcode)
13224 {
13225         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13226 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13227         switch (opcode) {
13228         case OP_LOAD_MEMBASE:
13229                 return OP_LOAD_MEM;
13230         case OP_LOADU1_MEMBASE:
13231                 return OP_LOADU1_MEM;
13232         case OP_LOADU2_MEMBASE:
13233                 return OP_LOADU2_MEM;
13234         case OP_LOADI4_MEMBASE:
13235                 return OP_LOADI4_MEM;
13236         case OP_LOADU4_MEMBASE:
13237                 return OP_LOADU4_MEM;
13238 #if SIZEOF_REGISTER == 8
13239         case OP_LOADI8_MEMBASE:
13240                 return OP_LOADI8_MEM;
13241 #endif
13242         }
13243 #endif
13244
13245         return -1;
13246 }
13247
13248 static inline int
13249 op_to_op_dest_membase (int store_opcode, int opcode)
13250 {
13251 #if defined(TARGET_X86)
13252         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13253                 return -1;
13254
13255         switch (opcode) {
13256         case OP_IADD:
13257                 return OP_X86_ADD_MEMBASE_REG;
13258         case OP_ISUB:
13259                 return OP_X86_SUB_MEMBASE_REG;
13260         case OP_IAND:
13261                 return OP_X86_AND_MEMBASE_REG;
13262         case OP_IOR:
13263                 return OP_X86_OR_MEMBASE_REG;
13264         case OP_IXOR:
13265                 return OP_X86_XOR_MEMBASE_REG;
13266         case OP_ADD_IMM:
13267         case OP_IADD_IMM:
13268                 return OP_X86_ADD_MEMBASE_IMM;
13269         case OP_SUB_IMM:
13270         case OP_ISUB_IMM:
13271                 return OP_X86_SUB_MEMBASE_IMM;
13272         case OP_AND_IMM:
13273         case OP_IAND_IMM:
13274                 return OP_X86_AND_MEMBASE_IMM;
13275         case OP_OR_IMM:
13276         case OP_IOR_IMM:
13277                 return OP_X86_OR_MEMBASE_IMM;
13278         case OP_XOR_IMM:
13279         case OP_IXOR_IMM:
13280                 return OP_X86_XOR_MEMBASE_IMM;
13281         case OP_MOVE:
13282                 return OP_NOP;
13283         }
13284 #endif
13285
13286 #if defined(TARGET_AMD64)
13287         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13288                 return -1;
13289
13290         switch (opcode) {
13291         case OP_IADD:
13292                 return OP_X86_ADD_MEMBASE_REG;
13293         case OP_ISUB:
13294                 return OP_X86_SUB_MEMBASE_REG;
13295         case OP_IAND:
13296                 return OP_X86_AND_MEMBASE_REG;
13297         case OP_IOR:
13298                 return OP_X86_OR_MEMBASE_REG;
13299         case OP_IXOR:
13300                 return OP_X86_XOR_MEMBASE_REG;
13301         case OP_IADD_IMM:
13302                 return OP_X86_ADD_MEMBASE_IMM;
13303         case OP_ISUB_IMM:
13304                 return OP_X86_SUB_MEMBASE_IMM;
13305         case OP_IAND_IMM:
13306                 return OP_X86_AND_MEMBASE_IMM;
13307         case OP_IOR_IMM:
13308                 return OP_X86_OR_MEMBASE_IMM;
13309         case OP_IXOR_IMM:
13310                 return OP_X86_XOR_MEMBASE_IMM;
13311         case OP_LADD:
13312                 return OP_AMD64_ADD_MEMBASE_REG;
13313         case OP_LSUB:
13314                 return OP_AMD64_SUB_MEMBASE_REG;
13315         case OP_LAND:
13316                 return OP_AMD64_AND_MEMBASE_REG;
13317         case OP_LOR:
13318                 return OP_AMD64_OR_MEMBASE_REG;
13319         case OP_LXOR:
13320                 return OP_AMD64_XOR_MEMBASE_REG;
13321         case OP_ADD_IMM:
13322         case OP_LADD_IMM:
13323                 return OP_AMD64_ADD_MEMBASE_IMM;
13324         case OP_SUB_IMM:
13325         case OP_LSUB_IMM:
13326                 return OP_AMD64_SUB_MEMBASE_IMM;
13327         case OP_AND_IMM:
13328         case OP_LAND_IMM:
13329                 return OP_AMD64_AND_MEMBASE_IMM;
13330         case OP_OR_IMM:
13331         case OP_LOR_IMM:
13332                 return OP_AMD64_OR_MEMBASE_IMM;
13333         case OP_XOR_IMM:
13334         case OP_LXOR_IMM:
13335                 return OP_AMD64_XOR_MEMBASE_IMM;
13336         case OP_MOVE:
13337                 return OP_NOP;
13338         }
13339 #endif
13340
13341         return -1;
13342 }
13343
13344 static inline int
13345 op_to_op_store_membase (int store_opcode, int opcode)
13346 {
13347 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13348         switch (opcode) {
13349         case OP_ICEQ:
13350                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13351                         return OP_X86_SETEQ_MEMBASE;
13352         case OP_CNE:
13353                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13354                         return OP_X86_SETNE_MEMBASE;
13355         }
13356 #endif
13357
13358         return -1;
13359 }
13360
13361 static inline int
13362 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13363 {
13364 #ifdef TARGET_X86
13365         /* FIXME: This has sign extension issues */
13366         /*
13367         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13368                 return OP_X86_COMPARE_MEMBASE8_IMM;
13369         */
13370
13371         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13372                 return -1;
13373
13374         switch (opcode) {
13375         case OP_X86_PUSH:
13376                 return OP_X86_PUSH_MEMBASE;
13377         case OP_COMPARE_IMM:
13378         case OP_ICOMPARE_IMM:
13379                 return OP_X86_COMPARE_MEMBASE_IMM;
13380         case OP_COMPARE:
13381         case OP_ICOMPARE:
13382                 return OP_X86_COMPARE_MEMBASE_REG;
13383         }
13384 #endif
13385
13386 #ifdef TARGET_AMD64
13387         /* FIXME: This has sign extension issues */
13388         /*
13389         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13390                 return OP_X86_COMPARE_MEMBASE8_IMM;
13391         */
13392
13393         switch (opcode) {
13394         case OP_X86_PUSH:
13395                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13396                         return OP_X86_PUSH_MEMBASE;
13397                 break;
13398                 /* FIXME: This only works for 32 bit immediates
13399         case OP_COMPARE_IMM:
13400         case OP_LCOMPARE_IMM:
13401                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13402                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13403                 */
13404         case OP_ICOMPARE_IMM:
13405                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13406                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13407                 break;
13408         case OP_COMPARE:
13409         case OP_LCOMPARE:
13410                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
13411                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13412                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13413                         return OP_AMD64_COMPARE_MEMBASE_REG;
13414                 break;
13415         case OP_ICOMPARE:
13416                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13417                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13418                 break;
13419         }
13420 #endif
13421
13422         return -1;
13423 }
13424
13425 static inline int
13426 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
13427 {
13428 #ifdef TARGET_X86
13429         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13430                 return -1;
13431         
13432         switch (opcode) {
13433         case OP_COMPARE:
13434         case OP_ICOMPARE:
13435                 return OP_X86_COMPARE_REG_MEMBASE;
13436         case OP_IADD:
13437                 return OP_X86_ADD_REG_MEMBASE;
13438         case OP_ISUB:
13439                 return OP_X86_SUB_REG_MEMBASE;
13440         case OP_IAND:
13441                 return OP_X86_AND_REG_MEMBASE;
13442         case OP_IOR:
13443                 return OP_X86_OR_REG_MEMBASE;
13444         case OP_IXOR:
13445                 return OP_X86_XOR_REG_MEMBASE;
13446         }
13447 #endif
13448
13449 #ifdef TARGET_AMD64
13450         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
13451                 switch (opcode) {
13452                 case OP_ICOMPARE:
13453                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13454                 case OP_IADD:
13455                         return OP_X86_ADD_REG_MEMBASE;
13456                 case OP_ISUB:
13457                         return OP_X86_SUB_REG_MEMBASE;
13458                 case OP_IAND:
13459                         return OP_X86_AND_REG_MEMBASE;
13460                 case OP_IOR:
13461                         return OP_X86_OR_REG_MEMBASE;
13462                 case OP_IXOR:
13463                         return OP_X86_XOR_REG_MEMBASE;
13464                 }
13465         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
13466                 switch (opcode) {
13467                 case OP_COMPARE:
13468                 case OP_LCOMPARE:
13469                         return OP_AMD64_COMPARE_REG_MEMBASE;
13470                 case OP_LADD:
13471                         return OP_AMD64_ADD_REG_MEMBASE;
13472                 case OP_LSUB:
13473                         return OP_AMD64_SUB_REG_MEMBASE;
13474                 case OP_LAND:
13475                         return OP_AMD64_AND_REG_MEMBASE;
13476                 case OP_LOR:
13477                         return OP_AMD64_OR_REG_MEMBASE;
13478                 case OP_LXOR:
13479                         return OP_AMD64_XOR_REG_MEMBASE;
13480                 }
13481         }
13482 #endif
13483
13484         return -1;
13485 }
13486
13487 int
13488 mono_op_to_op_imm_noemul (int opcode)
13489 {
13490         switch (opcode) {
13491 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13492         case OP_LSHR:
13493         case OP_LSHL:
13494         case OP_LSHR_UN:
13495                 return -1;
13496 #endif
13497 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13498         case OP_IDIV:
13499         case OP_IDIV_UN:
13500         case OP_IREM:
13501         case OP_IREM_UN:
13502                 return -1;
13503 #endif
13504 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13505         case OP_IMUL:
13506                 return -1;
13507 #endif
13508         default:
13509                 return mono_op_to_op_imm (opcode);
13510         }
13511 }
13512
13513 /**
13514  * mono_handle_global_vregs:
13515  *
13516  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13517  * for them.
13518  */
13519 void
13520 mono_handle_global_vregs (MonoCompile *cfg)
13521 {
13522         gint32 *vreg_to_bb;
13523         MonoBasicBlock *bb;
13524         int i, pos;
13525
13526         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13527
13528 #ifdef MONO_ARCH_SIMD_INTRINSICS
13529         if (cfg->uses_simd_intrinsics)
13530                 mono_simd_simplify_indirection (cfg);
13531 #endif
13532
13533         /* Find local vregs used in more than one bb */
13534         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13535                 MonoInst *ins = bb->code;       
13536                 int block_num = bb->block_num;
13537
13538                 if (cfg->verbose_level > 2)
13539                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13540
13541                 cfg->cbb = bb;
13542                 for (; ins; ins = ins->next) {
13543                         const char *spec = INS_INFO (ins->opcode);
13544                         int regtype = 0, regindex;
13545                         gint32 prev_bb;
13546
13547                         if (G_UNLIKELY (cfg->verbose_level > 2))
13548                                 mono_print_ins (ins);
13549
13550                         g_assert (ins->opcode >= MONO_CEE_LAST);
13551
13552                         for (regindex = 0; regindex < 4; regindex ++) {
13553                                 int vreg = 0;
13554
13555                                 if (regindex == 0) {
13556                                         regtype = spec [MONO_INST_DEST];
13557                                         if (regtype == ' ')
13558                                                 continue;
13559                                         vreg = ins->dreg;
13560                                 } else if (regindex == 1) {
13561                                         regtype = spec [MONO_INST_SRC1];
13562                                         if (regtype == ' ')
13563                                                 continue;
13564                                         vreg = ins->sreg1;
13565                                 } else if (regindex == 2) {
13566                                         regtype = spec [MONO_INST_SRC2];
13567                                         if (regtype == ' ')
13568                                                 continue;
13569                                         vreg = ins->sreg2;
13570                                 } else if (regindex == 3) {
13571                                         regtype = spec [MONO_INST_SRC3];
13572                                         if (regtype == ' ')
13573                                                 continue;
13574                                         vreg = ins->sreg3;
13575                                 }
13576
13577 #if SIZEOF_REGISTER == 4
13578                                 /* In the LLVM case, the long opcodes are not decomposed */
13579                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13580                                         /*
13581                                          * Since some instructions reference the original long vreg,
13582                                          * and some reference the two component vregs, it is quite hard
13583                                          * to determine when it needs to be global. So be conservative.
13584                                          */
13585                                         if (!get_vreg_to_inst (cfg, vreg)) {
13586                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13587
13588                                                 if (cfg->verbose_level > 2)
13589                                                         printf ("LONG VREG R%d made global.\n", vreg);
13590                                         }
13591
13592                                         /*
13593                                          * Make the component vregs volatile since the optimizations can
13594                                          * get confused otherwise.
13595                                          */
13596                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
13597                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
13598                                 }
13599 #endif
13600
13601                                 g_assert (vreg != -1);
13602
13603                                 prev_bb = vreg_to_bb [vreg];
13604                                 if (prev_bb == 0) {
13605                                         /* 0 is a valid block num */
13606                                         vreg_to_bb [vreg] = block_num + 1;
13607                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13608                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13609                                                 continue;
13610
13611                                         if (!get_vreg_to_inst (cfg, vreg)) {
13612                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13613                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13614
13615                                                 switch (regtype) {
13616                                                 case 'i':
13617                                                         if (vreg_is_ref (cfg, vreg))
13618                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13619                                                         else
13620                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13621                                                         break;
13622                                                 case 'l':
13623                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13624                                                         break;
13625                                                 case 'f':
13626                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13627                                                         break;
13628                                                 case 'v':
13629                                                 case 'x':
13630                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13631                                                         break;
13632                                                 default:
13633                                                         g_assert_not_reached ();
13634                                                 }
13635                                         }
13636
13637                                         /* Flag as having been used in more than one bb */
13638                                         vreg_to_bb [vreg] = -1;
13639                                 }
13640                         }
13641                 }
13642         }
13643
13644         /* If a variable is used in only one bblock, convert it into a local vreg */
13645         for (i = 0; i < cfg->num_varinfo; i++) {
13646                 MonoInst *var = cfg->varinfo [i];
13647                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13648
13649                 switch (var->type) {
13650                 case STACK_I4:
13651                 case STACK_OBJ:
13652                 case STACK_PTR:
13653                 case STACK_MP:
13654                 case STACK_VTYPE:
13655 #if SIZEOF_REGISTER == 8
13656                 case STACK_I8:
13657 #endif
13658 #if !defined(TARGET_X86)
13659                 /* Enabling this screws up the fp stack on x86 */
13660                 case STACK_R8:
13661 #endif
13662                         if (mono_arch_is_soft_float ())
13663                                 break;
13664
13665                         /*
13666                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
13667                                 break;
13668                         */
13669
13670                         /* Arguments are implicitly global */
13671                         /* Putting R4 vars into registers doesn't work currently */
13672                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13673                         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) {
13674                                 /* 
13675                                  * Make that the variable's liveness interval doesn't contain a call, since
13676                                  * that would cause the lvreg to be spilled, making the whole optimization
13677                                  * useless.
13678                                  */
13679                                 /* This is too slow for JIT compilation */
13680 #if 0
13681                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13682                                         MonoInst *ins;
13683                                         int def_index, call_index, ins_index;
13684                                         gboolean spilled = FALSE;
13685
13686                                         def_index = -1;
13687                                         call_index = -1;
13688                                         ins_index = 0;
13689                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13690                                                 const char *spec = INS_INFO (ins->opcode);
13691
13692                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13693                                                         def_index = ins_index;
13694
13695                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13696                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13697                                                         if (call_index > def_index) {
13698                                                                 spilled = TRUE;
13699                                                                 break;
13700                                                         }
13701                                                 }
13702
13703                                                 if (MONO_IS_CALL (ins))
13704                                                         call_index = ins_index;
13705
13706                                                 ins_index ++;
13707                                         }
13708
13709                                         if (spilled)
13710                                                 break;
13711                                 }
13712 #endif
13713
13714                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13715                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13716                                 var->flags |= MONO_INST_IS_DEAD;
13717                                 cfg->vreg_to_inst [var->dreg] = NULL;
13718                         }
13719                         break;
13720                 }
13721         }
13722
13723         /* 
13724          * Compress the varinfo and vars tables so the liveness computation is faster and
13725          * takes up less space.
13726          */
13727         pos = 0;
13728         for (i = 0; i < cfg->num_varinfo; ++i) {
13729                 MonoInst *var = cfg->varinfo [i];
13730                 if (pos < i && cfg->locals_start == i)
13731                         cfg->locals_start = pos;
13732                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13733                         if (pos < i) {
13734                                 cfg->varinfo [pos] = cfg->varinfo [i];
13735                                 cfg->varinfo [pos]->inst_c0 = pos;
13736                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13737                                 cfg->vars [pos].idx = pos;
13738 #if SIZEOF_REGISTER == 4
13739                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13740                                         /* Modify the two component vars too */
13741                                         MonoInst *var1;
13742
13743                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
13744                                         var1->inst_c0 = pos;
13745                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
13746                                         var1->inst_c0 = pos;
13747                                 }
13748 #endif
13749                         }
13750                         pos ++;
13751                 }
13752         }
13753         cfg->num_varinfo = pos;
13754         if (cfg->locals_start > cfg->num_varinfo)
13755                 cfg->locals_start = cfg->num_varinfo;
13756 }
13757
13758 /*
13759  * mono_allocate_gsharedvt_vars:
13760  *
13761  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
13762  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
13763  */
13764 void
13765 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
13766 {
13767         int i;
13768
13769         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13770
13771         for (i = 0; i < cfg->num_varinfo; ++i) {
13772                 MonoInst *ins = cfg->varinfo [i];
13773                 int idx;
13774
13775                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13776                         if (i >= cfg->locals_start) {
13777                                 /* Local */
13778                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13779                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13780                                 ins->opcode = OP_GSHAREDVT_LOCAL;
13781                                 ins->inst_imm = idx;
13782                         } else {
13783                                 /* Arg */
13784                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
13785                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13786                         }
13787                 }
13788         }
13789 }
13790
13791 /**
13792  * mono_spill_global_vars:
13793  *
13794  *   Generate spill code for variables which are not allocated to registers, 
13795  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13796  * code is generated which could be optimized by the local optimization passes.
13797  */
13798 void
13799 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13800 {
13801         MonoBasicBlock *bb;
13802         char spec2 [16];
13803         int orig_next_vreg;
13804         guint32 *vreg_to_lvreg;
13805         guint32 *lvregs;
13806         guint32 i, lvregs_len, lvregs_size;
13807         gboolean dest_has_lvreg = FALSE;
13808         MonoStackType stacktypes [128];
13809         MonoInst **live_range_start, **live_range_end;
13810         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13811
13812         *need_local_opts = FALSE;
13813
13814         memset (spec2, 0, sizeof (spec2));
13815
13816         /* FIXME: Move this function to mini.c */
13817         stacktypes ['i'] = STACK_PTR;
13818         stacktypes ['l'] = STACK_I8;
13819         stacktypes ['f'] = STACK_R8;
13820 #ifdef MONO_ARCH_SIMD_INTRINSICS
13821         stacktypes ['x'] = STACK_VTYPE;
13822 #endif
13823
13824 #if SIZEOF_REGISTER == 4
13825         /* Create MonoInsts for longs */
13826         for (i = 0; i < cfg->num_varinfo; i++) {
13827                 MonoInst *ins = cfg->varinfo [i];
13828
13829                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13830                         switch (ins->type) {
13831                         case STACK_R8:
13832                         case STACK_I8: {
13833                                 MonoInst *tree;
13834
13835                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13836                                         break;
13837
13838                                 g_assert (ins->opcode == OP_REGOFFSET);
13839
13840                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
13841                                 g_assert (tree);
13842                                 tree->opcode = OP_REGOFFSET;
13843                                 tree->inst_basereg = ins->inst_basereg;
13844                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13845
13846                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
13847                                 g_assert (tree);
13848                                 tree->opcode = OP_REGOFFSET;
13849                                 tree->inst_basereg = ins->inst_basereg;
13850                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13851                                 break;
13852                         }
13853                         default:
13854                                 break;
13855                         }
13856                 }
13857         }
13858 #endif
13859
13860         if (cfg->compute_gc_maps) {
13861                 /* registers need liveness info even for !non refs */
13862                 for (i = 0; i < cfg->num_varinfo; i++) {
13863                         MonoInst *ins = cfg->varinfo [i];
13864
13865                         if (ins->opcode == OP_REGVAR)
13866                                 ins->flags |= MONO_INST_GC_TRACK;
13867                 }
13868         }
13869                 
13870         /* FIXME: widening and truncation */
13871
13872         /*
13873          * As an optimization, when a variable allocated to the stack is first loaded into 
13874          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13875          * the variable again.
13876          */
13877         orig_next_vreg = cfg->next_vreg;
13878         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13879         lvregs_size = 1024;
13880         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * lvregs_size);
13881         lvregs_len = 0;
13882
13883         /* 
13884          * These arrays contain the first and last instructions accessing a given
13885          * variable.
13886          * Since we emit bblocks in the same order we process them here, and we
13887          * don't split live ranges, these will precisely describe the live range of
13888          * the variable, i.e. the instruction range where a valid value can be found
13889          * in the variables location.
13890          * The live range is computed using the liveness info computed by the liveness pass.
13891          * We can't use vmv->range, since that is an abstract live range, and we need
13892          * one which is instruction precise.
13893          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13894          */
13895         /* FIXME: Only do this if debugging info is requested */
13896         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13897         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13898         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13899         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13900         
13901         /* Add spill loads/stores */
13902         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13903                 MonoInst *ins;
13904
13905                 if (cfg->verbose_level > 2)
13906                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13907
13908                 /* Clear vreg_to_lvreg array */
13909                 for (i = 0; i < lvregs_len; i++)
13910                         vreg_to_lvreg [lvregs [i]] = 0;
13911                 lvregs_len = 0;
13912
13913                 cfg->cbb = bb;
13914                 MONO_BB_FOR_EACH_INS (bb, ins) {
13915                         const char *spec = INS_INFO (ins->opcode);
13916                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13917                         gboolean store, no_lvreg;
13918                         int sregs [MONO_MAX_SRC_REGS];
13919
13920                         if (G_UNLIKELY (cfg->verbose_level > 2))
13921                                 mono_print_ins (ins);
13922
13923                         if (ins->opcode == OP_NOP)
13924                                 continue;
13925
13926                         /* 
13927                          * We handle LDADDR here as well, since it can only be decomposed
13928                          * when variable addresses are known.
13929                          */
13930                         if (ins->opcode == OP_LDADDR) {
13931                                 MonoInst *var = (MonoInst *)ins->inst_p0;
13932
13933                                 if (var->opcode == OP_VTARG_ADDR) {
13934                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13935                                         MonoInst *vtaddr = var->inst_left;
13936                                         if (vtaddr->opcode == OP_REGVAR) {
13937                                                 ins->opcode = OP_MOVE;
13938                                                 ins->sreg1 = vtaddr->dreg;
13939                                         }
13940                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13941                                                 ins->opcode = OP_LOAD_MEMBASE;
13942                                                 ins->inst_basereg = vtaddr->inst_basereg;
13943                                                 ins->inst_offset = vtaddr->inst_offset;
13944                                         } else
13945                                                 NOT_IMPLEMENTED;
13946                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
13947                                         /* gsharedvt arg passed by ref */
13948                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13949
13950                                         ins->opcode = OP_LOAD_MEMBASE;
13951                                         ins->inst_basereg = var->inst_basereg;
13952                                         ins->inst_offset = var->inst_offset;
13953                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
13954                                         MonoInst *load, *load2, *load3;
13955                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
13956                                         int reg1, reg2, reg3;
13957                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13958                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13959
13960                                         /*
13961                                          * gsharedvt local.
13962                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13963                                          */
13964
13965                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13966
13967                                         g_assert (info_var);
13968                                         g_assert (locals_var);
13969
13970                                         /* Mark the instruction used to compute the locals var as used */
13971                                         cfg->gsharedvt_locals_var_ins = NULL;
13972
13973                                         /* Load the offset */
13974                                         if (info_var->opcode == OP_REGOFFSET) {
13975                                                 reg1 = alloc_ireg (cfg);
13976                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13977                                         } else if (info_var->opcode == OP_REGVAR) {
13978                                                 load = NULL;
13979                                                 reg1 = info_var->dreg;
13980                                         } else {
13981                                                 g_assert_not_reached ();
13982                                         }
13983                                         reg2 = alloc_ireg (cfg);
13984                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13985                                         /* Load the locals area address */
13986                                         reg3 = alloc_ireg (cfg);
13987                                         if (locals_var->opcode == OP_REGOFFSET) {
13988                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13989                                         } else if (locals_var->opcode == OP_REGVAR) {
13990                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13991                                         } else {
13992                                                 g_assert_not_reached ();
13993                                         }
13994                                         /* Compute the address */
13995                                         ins->opcode = OP_PADD;
13996                                         ins->sreg1 = reg3;
13997                                         ins->sreg2 = reg2;
13998
13999                                         mono_bblock_insert_before_ins (bb, ins, load3);
14000                                         mono_bblock_insert_before_ins (bb, load3, load2);
14001                                         if (load)
14002                                                 mono_bblock_insert_before_ins (bb, load2, load);
14003                                 } else {
14004                                         g_assert (var->opcode == OP_REGOFFSET);
14005
14006                                         ins->opcode = OP_ADD_IMM;
14007                                         ins->sreg1 = var->inst_basereg;
14008                                         ins->inst_imm = var->inst_offset;
14009                                 }
14010
14011                                 *need_local_opts = TRUE;
14012                                 spec = INS_INFO (ins->opcode);
14013                         }
14014
14015                         if (ins->opcode < MONO_CEE_LAST) {
14016                                 mono_print_ins (ins);
14017                                 g_assert_not_reached ();
14018                         }
14019
14020                         /*
14021                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14022                          * src register.
14023                          * FIXME:
14024                          */
14025                         if (MONO_IS_STORE_MEMBASE (ins)) {
14026                                 tmp_reg = ins->dreg;
14027                                 ins->dreg = ins->sreg2;
14028                                 ins->sreg2 = tmp_reg;
14029                                 store = TRUE;
14030
14031                                 spec2 [MONO_INST_DEST] = ' ';
14032                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14033                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14034                                 spec2 [MONO_INST_SRC3] = ' ';
14035                                 spec = spec2;
14036                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14037                                 g_assert_not_reached ();
14038                         else
14039                                 store = FALSE;
14040                         no_lvreg = FALSE;
14041
14042                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14043                                 printf ("\t %.3s %d", spec, ins->dreg);
14044                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14045                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14046                                         printf (" %d", sregs [srcindex]);
14047                                 printf ("\n");
14048                         }
14049
14050                         /***************/
14051                         /*    DREG     */
14052                         /***************/
14053                         regtype = spec [MONO_INST_DEST];
14054                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14055                         prev_dreg = -1;
14056
14057                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14058                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14059                                 MonoInst *store_ins;
14060                                 int store_opcode;
14061                                 MonoInst *def_ins = ins;
14062                                 int dreg = ins->dreg; /* The original vreg */
14063
14064                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14065
14066                                 if (var->opcode == OP_REGVAR) {
14067                                         ins->dreg = var->dreg;
14068                                 } 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)) {
14069                                         /* 
14070                                          * Instead of emitting a load+store, use a _membase opcode.
14071                                          */
14072                                         g_assert (var->opcode == OP_REGOFFSET);
14073                                         if (ins->opcode == OP_MOVE) {
14074                                                 NULLIFY_INS (ins);
14075                                                 def_ins = NULL;
14076                                         } else {
14077                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14078                                                 ins->inst_basereg = var->inst_basereg;
14079                                                 ins->inst_offset = var->inst_offset;
14080                                                 ins->dreg = -1;
14081                                         }
14082                                         spec = INS_INFO (ins->opcode);
14083                                 } else {
14084                                         guint32 lvreg;
14085
14086                                         g_assert (var->opcode == OP_REGOFFSET);
14087
14088                                         prev_dreg = ins->dreg;
14089
14090                                         /* Invalidate any previous lvreg for this vreg */
14091                                         vreg_to_lvreg [ins->dreg] = 0;
14092
14093                                         lvreg = 0;
14094
14095                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14096                                                 regtype = 'l';
14097                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14098                                         }
14099
14100                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14101
14102 #if SIZEOF_REGISTER != 8
14103                                         if (regtype == 'l') {
14104                                                 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));
14105                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14106                                                 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));
14107                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14108                                                 def_ins = store_ins;
14109                                         }
14110                                         else
14111 #endif
14112                                         {
14113                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14114
14115                                                 /* Try to fuse the store into the instruction itself */
14116                                                 /* FIXME: Add more instructions */
14117                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14118                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14119                                                         ins->inst_imm = ins->inst_c0;
14120                                                         ins->inst_destbasereg = var->inst_basereg;
14121                                                         ins->inst_offset = var->inst_offset;
14122                                                         spec = INS_INFO (ins->opcode);
14123                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14124                                                         ins->opcode = store_opcode;
14125                                                         ins->inst_destbasereg = var->inst_basereg;
14126                                                         ins->inst_offset = var->inst_offset;
14127
14128                                                         no_lvreg = TRUE;
14129
14130                                                         tmp_reg = ins->dreg;
14131                                                         ins->dreg = ins->sreg2;
14132                                                         ins->sreg2 = tmp_reg;
14133                                                         store = TRUE;
14134
14135                                                         spec2 [MONO_INST_DEST] = ' ';
14136                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14137                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14138                                                         spec2 [MONO_INST_SRC3] = ' ';
14139                                                         spec = spec2;
14140                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14141                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14142                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14143                                                         ins->dreg = -1;
14144                                                         ins->inst_basereg = var->inst_basereg;
14145                                                         ins->inst_offset = var->inst_offset;
14146                                                         spec = INS_INFO (ins->opcode);
14147                                                 } else {
14148                                                         /* printf ("INS: "); mono_print_ins (ins); */
14149                                                         /* Create a store instruction */
14150                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14151
14152                                                         /* Insert it after the instruction */
14153                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14154
14155                                                         def_ins = store_ins;
14156
14157                                                         /* 
14158                                                          * We can't assign ins->dreg to var->dreg here, since the
14159                                                          * sregs could use it. So set a flag, and do it after
14160                                                          * the sregs.
14161                                                          */
14162                                                         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)))
14163                                                                 dest_has_lvreg = TRUE;
14164                                                 }
14165                                         }
14166                                 }
14167
14168                                 if (def_ins && !live_range_start [dreg]) {
14169                                         live_range_start [dreg] = def_ins;
14170                                         live_range_start_bb [dreg] = bb;
14171                                 }
14172
14173                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14174                                         MonoInst *tmp;
14175
14176                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14177                                         tmp->inst_c1 = dreg;
14178                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14179                                 }
14180                         }
14181
14182                         /************/
14183                         /*  SREGS   */
14184                         /************/
14185                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14186                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14187                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14188                                 sreg = sregs [srcindex];
14189
14190                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14191                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14192                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14193                                         MonoInst *use_ins = ins;
14194                                         MonoInst *load_ins;
14195                                         guint32 load_opcode;
14196
14197                                         if (var->opcode == OP_REGVAR) {
14198                                                 sregs [srcindex] = var->dreg;
14199                                                 //mono_inst_set_src_registers (ins, sregs);
14200                                                 live_range_end [sreg] = use_ins;
14201                                                 live_range_end_bb [sreg] = bb;
14202
14203                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14204                                                         MonoInst *tmp;
14205
14206                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14207                                                         /* var->dreg is a hreg */
14208                                                         tmp->inst_c1 = sreg;
14209                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14210                                                 }
14211
14212                                                 continue;
14213                                         }
14214
14215                                         g_assert (var->opcode == OP_REGOFFSET);
14216                                                 
14217                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14218
14219                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14220
14221                                         if (vreg_to_lvreg [sreg]) {
14222                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14223
14224                                                 /* The variable is already loaded to an lvreg */
14225                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14226                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14227                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14228                                                 //mono_inst_set_src_registers (ins, sregs);
14229                                                 continue;
14230                                         }
14231
14232                                         /* Try to fuse the load into the instruction */
14233                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14234                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14235                                                 sregs [0] = var->inst_basereg;
14236                                                 //mono_inst_set_src_registers (ins, sregs);
14237                                                 ins->inst_offset = var->inst_offset;
14238                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14239                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14240                                                 sregs [1] = var->inst_basereg;
14241                                                 //mono_inst_set_src_registers (ins, sregs);
14242                                                 ins->inst_offset = var->inst_offset;
14243                                         } else {
14244                                                 if (MONO_IS_REAL_MOVE (ins)) {
14245                                                         ins->opcode = OP_NOP;
14246                                                         sreg = ins->dreg;
14247                                                 } else {
14248                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14249
14250                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14251
14252                                                         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) {
14253                                                                 if (var->dreg == prev_dreg) {
14254                                                                         /*
14255                                                                          * sreg refers to the value loaded by the load
14256                                                                          * emitted below, but we need to use ins->dreg
14257                                                                          * since it refers to the store emitted earlier.
14258                                                                          */
14259                                                                         sreg = ins->dreg;
14260                                                                 }
14261                                                                 g_assert (sreg != -1);
14262                                                                 vreg_to_lvreg [var->dreg] = sreg;
14263                                                                 if (lvregs_len >= lvregs_size) {
14264                                                                         guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
14265                                                                         memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
14266                                                                         lvregs = new_lvregs;
14267                                                                         lvregs_size *= 2;
14268                                                                 }
14269                                                                 lvregs [lvregs_len ++] = var->dreg;
14270                                                         }
14271                                                 }
14272
14273                                                 sregs [srcindex] = sreg;
14274                                                 //mono_inst_set_src_registers (ins, sregs);
14275
14276 #if SIZEOF_REGISTER != 8
14277                                                 if (regtype == 'l') {
14278                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14279                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14280                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14281                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14282                                                         use_ins = load_ins;
14283                                                 }
14284                                                 else
14285 #endif
14286                                                 {
14287 #if SIZEOF_REGISTER == 4
14288                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14289 #endif
14290                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14291                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14292                                                         use_ins = load_ins;
14293                                                 }
14294                                         }
14295
14296                                         if (var->dreg < orig_next_vreg) {
14297                                                 live_range_end [var->dreg] = use_ins;
14298                                                 live_range_end_bb [var->dreg] = bb;
14299                                         }
14300
14301                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14302                                                 MonoInst *tmp;
14303
14304                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14305                                                 tmp->inst_c1 = var->dreg;
14306                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14307                                         }
14308                                 }
14309                         }
14310                         mono_inst_set_src_registers (ins, sregs);
14311
14312                         if (dest_has_lvreg) {
14313                                 g_assert (ins->dreg != -1);
14314                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14315                                 if (lvregs_len >= lvregs_size) {
14316                                         guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
14317                                         memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
14318                                         lvregs = new_lvregs;
14319                                         lvregs_size *= 2;
14320                                 }
14321                                 lvregs [lvregs_len ++] = prev_dreg;
14322                                 dest_has_lvreg = FALSE;
14323                         }
14324
14325                         if (store) {
14326                                 tmp_reg = ins->dreg;
14327                                 ins->dreg = ins->sreg2;
14328                                 ins->sreg2 = tmp_reg;
14329                         }
14330
14331                         if (MONO_IS_CALL (ins)) {
14332                                 /* Clear vreg_to_lvreg array */
14333                                 for (i = 0; i < lvregs_len; i++)
14334                                         vreg_to_lvreg [lvregs [i]] = 0;
14335                                 lvregs_len = 0;
14336                         } else if (ins->opcode == OP_NOP) {
14337                                 ins->dreg = -1;
14338                                 MONO_INST_NULLIFY_SREGS (ins);
14339                         }
14340
14341                         if (cfg->verbose_level > 2)
14342                                 mono_print_ins_index (1, ins);
14343                 }
14344
14345                 /* Extend the live range based on the liveness info */
14346                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14347                         for (i = 0; i < cfg->num_varinfo; i ++) {
14348                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14349
14350                                 if (vreg_is_volatile (cfg, vi->vreg))
14351                                         /* The liveness info is incomplete */
14352                                         continue;
14353
14354                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14355                                         /* Live from at least the first ins of this bb */
14356                                         live_range_start [vi->vreg] = bb->code;
14357                                         live_range_start_bb [vi->vreg] = bb;
14358                                 }
14359
14360                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14361                                         /* Live at least until the last ins of this bb */
14362                                         live_range_end [vi->vreg] = bb->last_ins;
14363                                         live_range_end_bb [vi->vreg] = bb;
14364                                 }
14365                         }
14366                 }
14367         }
14368         
14369         /*
14370          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14371          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14372          */
14373         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14374                 for (i = 0; i < cfg->num_varinfo; ++i) {
14375                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14376                         MonoInst *ins;
14377
14378                         if (live_range_start [vreg]) {
14379                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14380                                 ins->inst_c0 = i;
14381                                 ins->inst_c1 = vreg;
14382                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14383                         }
14384                         if (live_range_end [vreg]) {
14385                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14386                                 ins->inst_c0 = i;
14387                                 ins->inst_c1 = vreg;
14388                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14389                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14390                                 else
14391                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14392                         }
14393                 }
14394         }
14395
14396         if (cfg->gsharedvt_locals_var_ins) {
14397                 /* Nullify if unused */
14398                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14399                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14400         }
14401
14402         g_free (live_range_start);
14403         g_free (live_range_end);
14404         g_free (live_range_start_bb);
14405         g_free (live_range_end_bb);
14406 }
14407
14408
14409 /**
14410  * FIXME:
14411  * - use 'iadd' instead of 'int_add'
14412  * - handling ovf opcodes: decompose in method_to_ir.
14413  * - unify iregs/fregs
14414  *   -> partly done, the missing parts are:
14415  *   - a more complete unification would involve unifying the hregs as well, so
14416  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14417  *     would no longer map to the machine hregs, so the code generators would need to
14418  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14419  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14420  *     fp/non-fp branches speeds it up by about 15%.
14421  * - use sext/zext opcodes instead of shifts
14422  * - add OP_ICALL
14423  * - get rid of TEMPLOADs if possible and use vregs instead
14424  * - clean up usage of OP_P/OP_ opcodes
14425  * - cleanup usage of DUMMY_USE
14426  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14427  *   stack
14428  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14429  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14430  * - make sure handle_stack_args () is called before the branch is emitted
14431  * - when the new IR is done, get rid of all unused stuff
14432  * - COMPARE/BEQ as separate instructions or unify them ?
14433  *   - keeping them separate allows specialized compare instructions like
14434  *     compare_imm, compare_membase
14435  *   - most back ends unify fp compare+branch, fp compare+ceq
14436  * - integrate mono_save_args into inline_method
14437  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14438  * - handle long shift opts on 32 bit platforms somehow: they require 
14439  *   3 sregs (2 for arg1 and 1 for arg2)
14440  * - make byref a 'normal' type.
14441  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14442  *   variable if needed.
14443  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14444  *   like inline_method.
14445  * - remove inlining restrictions
14446  * - fix LNEG and enable cfold of INEG
14447  * - generalize x86 optimizations like ldelema as a peephole optimization
14448  * - add store_mem_imm for amd64
14449  * - optimize the loading of the interruption flag in the managed->native wrappers
14450  * - avoid special handling of OP_NOP in passes
14451  * - move code inserting instructions into one function/macro.
14452  * - try a coalescing phase after liveness analysis
14453  * - add float -> vreg conversion + local optimizations on !x86
14454  * - figure out how to handle decomposed branches during optimizations, ie.
14455  *   compare+branch, op_jump_table+op_br etc.
14456  * - promote RuntimeXHandles to vregs
14457  * - vtype cleanups:
14458  *   - add a NEW_VARLOADA_VREG macro
14459  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14460  *   accessing vtype fields.
14461  * - get rid of I8CONST on 64 bit platforms
14462  * - dealing with the increase in code size due to branches created during opcode
14463  *   decomposition:
14464  *   - use extended basic blocks
14465  *     - all parts of the JIT
14466  *     - handle_global_vregs () && local regalloc
14467  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14468  * - sources of increase in code size:
14469  *   - vtypes
14470  *   - long compares
14471  *   - isinst and castclass
14472  *   - lvregs not allocated to global registers even if used multiple times
14473  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14474  *   meaningful.
14475  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14476  * - add all micro optimizations from the old JIT
14477  * - put tree optimizations into the deadce pass
14478  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14479  *   specific function.
14480  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14481  *   fcompare + branchCC.
14482  * - create a helper function for allocating a stack slot, taking into account 
14483  *   MONO_CFG_HAS_SPILLUP.
14484  * - merge r68207.
14485  * - merge the ia64 switch changes.
14486  * - optimize mono_regstate2_alloc_int/float.
14487  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14488  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14489  *   parts of the tree could be separated by other instructions, killing the tree
14490  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14491  *   instructions if the result of the load is used multiple times ?
14492  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14493  * - LAST MERGE: 108395.
14494  * - when returning vtypes in registers, generate IR and append it to the end of the
14495  *   last bb instead of doing it in the epilog.
14496  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14497  */
14498
14499 /*
14500
14501 NOTES
14502 -----
14503
14504 - When to decompose opcodes:
14505   - earlier: this makes some optimizations hard to implement, since the low level IR
14506   no longer contains the neccessary information. But it is easier to do.
14507   - later: harder to implement, enables more optimizations.
14508 - Branches inside bblocks:
14509   - created when decomposing complex opcodes. 
14510     - branches to another bblock: harmless, but not tracked by the branch 
14511       optimizations, so need to branch to a label at the start of the bblock.
14512     - branches to inside the same bblock: very problematic, trips up the local
14513       reg allocator. Can be fixed by spitting the current bblock, but that is a
14514       complex operation, since some local vregs can become global vregs etc.
14515 - Local/global vregs:
14516   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14517     local register allocator.
14518   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14519     structure, created by mono_create_var (). Assigned to hregs or the stack by
14520     the global register allocator.
14521 - When to do optimizations like alu->alu_imm:
14522   - earlier -> saves work later on since the IR will be smaller/simpler
14523   - later -> can work on more instructions
14524 - Handling of valuetypes:
14525   - When a vtype is pushed on the stack, a new temporary is created, an 
14526     instruction computing its address (LDADDR) is emitted and pushed on
14527     the stack. Need to optimize cases when the vtype is used immediately as in
14528     argument passing, stloc etc.
14529 - Instead of the to_end stuff in the old JIT, simply call the function handling
14530   the values on the stack before emitting the last instruction of the bb.
14531 */
14532
14533 #else /* !DISABLE_JIT */
14534
14535 MONO_EMPTY_SOURCE_FILE (method_to_ir);
14536
14537 #endif /* !DISABLE_JIT */