Merge pull request #4014 from BrzVlad/feature-tls-refactor
[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                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6510
6511                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6512                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6513
6514                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6515                         MonoBasicBlock *prev = ebblock->in_bb [0];
6516
6517                         if (prev->next_bb == ebblock) {
6518                                 mono_merge_basic_blocks (cfg, prev, ebblock);
6519                                 cfg->cbb = prev;
6520                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6521                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
6522                                         cfg->cbb = prev_cbb;
6523                                 }
6524                         } else {
6525                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
6526                                 cfg->cbb = ebblock;
6527                         }
6528                 } else {
6529                         /* 
6530                          * Its possible that the rvar is set in some prev bblock, but not in others.
6531                          * (#1835).
6532                          */
6533                         if (rvar) {
6534                                 MonoBasicBlock *bb;
6535
6536                                 for (i = 0; i < ebblock->in_count; ++i) {
6537                                         bb = ebblock->in_bb [i];
6538
6539                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6540                                                 cfg->cbb = bb;
6541
6542                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6543                                         }
6544                                 }
6545                         }
6546
6547                         cfg->cbb = ebblock;
6548                 }
6549
6550                 if (rvar) {
6551                         /*
6552                          * If the inlined method contains only a throw, then the ret var is not 
6553                          * set, so set it to a dummy value.
6554                          */
6555                         if (!ret_var_set)
6556                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6557
6558                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6559                         *sp++ = ins;
6560                 }
6561                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6562                 return costs + 1;
6563         } else {
6564                 if (cfg->verbose_level > 2)
6565                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6566                 cfg->exception_type = MONO_EXCEPTION_NONE;
6567
6568                 /* This gets rid of the newly added bblocks */
6569                 cfg->cbb = prev_cbb;
6570         }
6571         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6572         return 0;
6573 }
6574
6575 /*
6576  * Some of these comments may well be out-of-date.
6577  * Design decisions: we do a single pass over the IL code (and we do bblock 
6578  * splitting/merging in the few cases when it's required: a back jump to an IL
6579  * address that was not already seen as bblock starting point).
6580  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6581  * Complex operations are decomposed in simpler ones right away. We need to let the 
6582  * arch-specific code peek and poke inside this process somehow (except when the 
6583  * optimizations can take advantage of the full semantic info of coarse opcodes).
6584  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6585  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6586  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6587  * opcode with value bigger than OP_LAST.
6588  * At this point the IR can be handed over to an interpreter, a dumb code generator
6589  * or to the optimizing code generator that will translate it to SSA form.
6590  *
6591  * Profiling directed optimizations.
6592  * We may compile by default with few or no optimizations and instrument the code
6593  * or the user may indicate what methods to optimize the most either in a config file
6594  * or through repeated runs where the compiler applies offline the optimizations to 
6595  * each method and then decides if it was worth it.
6596  */
6597
6598 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6599 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6600 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6601 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6602 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6603 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6604 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6605 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
6606
6607 /* offset from br.s -> br like opcodes */
6608 #define BIG_BRANCH_OFFSET 13
6609
6610 static gboolean
6611 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6612 {
6613         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6614
6615         return b == NULL || b == bb;
6616 }
6617
6618 static int
6619 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6620 {
6621         unsigned char *ip = start;
6622         unsigned char *target;
6623         int i;
6624         guint cli_addr;
6625         MonoBasicBlock *bblock;
6626         const MonoOpcode *opcode;
6627
6628         while (ip < end) {
6629                 cli_addr = ip - start;
6630                 i = mono_opcode_value ((const guint8 **)&ip, end);
6631                 if (i < 0)
6632                         UNVERIFIED;
6633                 opcode = &mono_opcodes [i];
6634                 switch (opcode->argument) {
6635                 case MonoInlineNone:
6636                         ip++; 
6637                         break;
6638                 case MonoInlineString:
6639                 case MonoInlineType:
6640                 case MonoInlineField:
6641                 case MonoInlineMethod:
6642                 case MonoInlineTok:
6643                 case MonoInlineSig:
6644                 case MonoShortInlineR:
6645                 case MonoInlineI:
6646                         ip += 5;
6647                         break;
6648                 case MonoInlineVar:
6649                         ip += 3;
6650                         break;
6651                 case MonoShortInlineVar:
6652                 case MonoShortInlineI:
6653                         ip += 2;
6654                         break;
6655                 case MonoShortInlineBrTarget:
6656                         target = start + cli_addr + 2 + (signed char)ip [1];
6657                         GET_BBLOCK (cfg, bblock, target);
6658                         ip += 2;
6659                         if (ip < end)
6660                                 GET_BBLOCK (cfg, bblock, ip);
6661                         break;
6662                 case MonoInlineBrTarget:
6663                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6664                         GET_BBLOCK (cfg, bblock, target);
6665                         ip += 5;
6666                         if (ip < end)
6667                                 GET_BBLOCK (cfg, bblock, ip);
6668                         break;
6669                 case MonoInlineSwitch: {
6670                         guint32 n = read32 (ip + 1);
6671                         guint32 j;
6672                         ip += 5;
6673                         cli_addr += 5 + 4 * n;
6674                         target = start + cli_addr;
6675                         GET_BBLOCK (cfg, bblock, target);
6676                         
6677                         for (j = 0; j < n; ++j) {
6678                                 target = start + cli_addr + (gint32)read32 (ip);
6679                                 GET_BBLOCK (cfg, bblock, target);
6680                                 ip += 4;
6681                         }
6682                         break;
6683                 }
6684                 case MonoInlineR:
6685                 case MonoInlineI8:
6686                         ip += 9;
6687                         break;
6688                 default:
6689                         g_assert_not_reached ();
6690                 }
6691
6692                 if (i == CEE_THROW) {
6693                         unsigned char *bb_start = ip - 1;
6694                         
6695                         /* Find the start of the bblock containing the throw */
6696                         bblock = NULL;
6697                         while ((bb_start >= start) && !bblock) {
6698                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6699                                 bb_start --;
6700                         }
6701                         if (bblock)
6702                                 bblock->out_of_line = 1;
6703                 }
6704         }
6705         return 0;
6706 unverified:
6707 exception_exit:
6708         *pos = ip;
6709         return 1;
6710 }
6711
6712 static inline MonoMethod *
6713 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
6714 {
6715         MonoMethod *method;
6716
6717         mono_error_init (error);
6718
6719         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6720                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
6721                 if (context) {
6722                         method = mono_class_inflate_generic_method_checked (method, context, error);
6723                 }
6724         } else {
6725                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
6726         }
6727
6728         return method;
6729 }
6730
6731 static inline MonoMethod *
6732 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6733 {
6734         MonoError error;
6735         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
6736
6737         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
6738                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
6739                 method = NULL;
6740         }
6741
6742         if (!method && !cfg)
6743                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6744
6745         return method;
6746 }
6747
6748 static inline MonoClass*
6749 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6750 {
6751         MonoError error;
6752         MonoClass *klass;
6753
6754         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6755                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
6756                 if (context) {
6757                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
6758                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6759                 }
6760         } else {
6761                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
6762                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6763         }
6764         if (klass)
6765                 mono_class_init (klass);
6766         return klass;
6767 }
6768
6769 static inline MonoMethodSignature*
6770 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
6771 {
6772         MonoMethodSignature *fsig;
6773
6774         mono_error_init (error);
6775         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6776                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6777         } else {
6778                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
6779                 return_val_if_nok (error, NULL);
6780         }
6781         if (context) {
6782                 fsig = mono_inflate_generic_signature(fsig, context, error);
6783         }
6784         return fsig;
6785 }
6786
6787 static MonoMethod*
6788 throw_exception (void)
6789 {
6790         static MonoMethod *method = NULL;
6791
6792         if (!method) {
6793                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6794                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6795         }
6796         g_assert (method);
6797         return method;
6798 }
6799
6800 static void
6801 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6802 {
6803         MonoMethod *thrower = throw_exception ();
6804         MonoInst *args [1];
6805
6806         EMIT_NEW_PCONST (cfg, args [0], ex);
6807         mono_emit_method_call (cfg, thrower, args, NULL);
6808 }
6809
6810 /*
6811  * Return the original method is a wrapper is specified. We can only access 
6812  * the custom attributes from the original method.
6813  */
6814 static MonoMethod*
6815 get_original_method (MonoMethod *method)
6816 {
6817         if (method->wrapper_type == MONO_WRAPPER_NONE)
6818                 return method;
6819
6820         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6821         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6822                 return NULL;
6823
6824         /* in other cases we need to find the original method */
6825         return mono_marshal_method_from_wrapper (method);
6826 }
6827
6828 static void
6829 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
6830 {
6831         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6832         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6833         if (ex)
6834                 emit_throw_exception (cfg, ex);
6835 }
6836
6837 static void
6838 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6839 {
6840         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6841         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6842         if (ex)
6843                 emit_throw_exception (cfg, ex);
6844 }
6845
6846 /*
6847  * Check that the IL instructions at ip are the array initialization
6848  * sequence and return the pointer to the data and the size.
6849  */
6850 static const char*
6851 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6852 {
6853         /*
6854          * newarr[System.Int32]
6855          * dup
6856          * ldtoken field valuetype ...
6857          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6858          */
6859         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6860                 MonoError error;
6861                 guint32 token = read32 (ip + 7);
6862                 guint32 field_token = read32 (ip + 2);
6863                 guint32 field_index = field_token & 0xffffff;
6864                 guint32 rva;
6865                 const char *data_ptr;
6866                 int size = 0;
6867                 MonoMethod *cmethod;
6868                 MonoClass *dummy_class;
6869                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
6870                 int dummy_align;
6871
6872                 if (!field) {
6873                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6874                         return NULL;
6875                 }
6876
6877                 *out_field_token = field_token;
6878
6879                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6880                 if (!cmethod)
6881                         return NULL;
6882                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6883                         return NULL;
6884                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6885                 case MONO_TYPE_BOOLEAN:
6886                 case MONO_TYPE_I1:
6887                 case MONO_TYPE_U1:
6888                         size = 1; break;
6889                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6890 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6891                 case MONO_TYPE_CHAR:
6892                 case MONO_TYPE_I2:
6893                 case MONO_TYPE_U2:
6894                         size = 2; break;
6895                 case MONO_TYPE_I4:
6896                 case MONO_TYPE_U4:
6897                 case MONO_TYPE_R4:
6898                         size = 4; break;
6899                 case MONO_TYPE_R8:
6900                 case MONO_TYPE_I8:
6901                 case MONO_TYPE_U8:
6902                         size = 8; break;
6903 #endif
6904                 default:
6905                         return NULL;
6906                 }
6907                 size *= len;
6908                 if (size > mono_type_size (field->type, &dummy_align))
6909                     return NULL;
6910                 *out_size = size;
6911                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6912                 if (!image_is_dynamic (method->klass->image)) {
6913                         field_index = read32 (ip + 2) & 0xffffff;
6914                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6915                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6916                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6917                         /* for aot code we do the lookup on load */
6918                         if (aot && data_ptr)
6919                                 return (const char *)GUINT_TO_POINTER (rva);
6920                 } else {
6921                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6922                         g_assert (!aot);
6923                         data_ptr = mono_field_get_data (field);
6924                 }
6925                 return data_ptr;
6926         }
6927         return NULL;
6928 }
6929
6930 static void
6931 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6932 {
6933         MonoError error;
6934         char *method_fname = mono_method_full_name (method, TRUE);
6935         char *method_code;
6936         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
6937
6938         if (!header) {
6939                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
6940                 mono_error_cleanup (&error);
6941         } else if (header->code_size == 0)
6942                 method_code = g_strdup ("method body is empty.");
6943         else
6944                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6945         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
6946         g_free (method_fname);
6947         g_free (method_code);
6948         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6949 }
6950
6951 static void
6952 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6953 {
6954         MonoInst *ins;
6955         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6956         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6957                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6958                 /* Optimize reg-reg moves away */
6959                 /* 
6960                  * Can't optimize other opcodes, since sp[0] might point to
6961                  * the last ins of a decomposed opcode.
6962                  */
6963                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6964         } else {
6965                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6966         }
6967 }
6968
6969 /*
6970  * ldloca inhibits many optimizations so try to get rid of it in common
6971  * cases.
6972  */
6973 static inline unsigned char *
6974 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6975 {
6976         int local, token;
6977         MonoClass *klass;
6978         MonoType *type;
6979
6980         if (size == 1) {
6981                 local = ip [1];
6982                 ip += 2;
6983         } else {
6984                 local = read16 (ip + 2);
6985                 ip += 4;
6986         }
6987         
6988         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6989                 /* From the INITOBJ case */
6990                 token = read32 (ip + 2);
6991                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6992                 CHECK_TYPELOAD (klass);
6993                 type = mini_get_underlying_type (&klass->byval_arg);
6994                 emit_init_local (cfg, local, type, TRUE);
6995                 return ip + 6;
6996         }
6997  exception_exit:
6998         return NULL;
6999 }
7000
7001 static MonoInst*
7002 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7003 {
7004         MonoInst *icall_args [16];
7005         MonoInst *call_target, *ins, *vtable_ins;
7006         int arg_reg, this_reg, vtable_reg;
7007         gboolean is_iface = mono_class_is_interface (cmethod->klass);
7008         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7009         gboolean variant_iface = FALSE;
7010         guint32 slot;
7011         int offset;
7012
7013         /*
7014          * In llvm-only mode, vtables contain function descriptors instead of
7015          * method addresses/trampolines.
7016          */
7017         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7018
7019         if (is_iface)
7020                 slot = mono_method_get_imt_slot (cmethod);
7021         else
7022                 slot = mono_method_get_vtable_index (cmethod);
7023
7024         this_reg = sp [0]->dreg;
7025
7026         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7027                 variant_iface = TRUE;
7028
7029         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7030                 /*
7031                  * The simplest case, a normal virtual call.
7032                  */
7033                 int slot_reg = alloc_preg (cfg);
7034                 int addr_reg = alloc_preg (cfg);
7035                 int arg_reg = alloc_preg (cfg);
7036                 MonoBasicBlock *non_null_bb;
7037
7038                 vtable_reg = alloc_preg (cfg);
7039                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7040                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7041
7042                 /* Load the vtable slot, which contains a function descriptor. */
7043                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7044
7045                 NEW_BBLOCK (cfg, non_null_bb);
7046
7047                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7048                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7049                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7050
7051                 /* Slow path */
7052                 // FIXME: Make the wrapper use the preserveall cconv
7053                 // FIXME: Use one icall per slot for small slot numbers ?
7054                 icall_args [0] = vtable_ins;
7055                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7056                 /* Make the icall return the vtable slot value to save some code space */
7057                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7058                 ins->dreg = slot_reg;
7059                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7060
7061                 /* Fastpath */
7062                 MONO_START_BB (cfg, non_null_bb);
7063                 /* Load the address + arg from the vtable slot */
7064                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7065                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7066
7067                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7068         }
7069
7070         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7071                 /*
7072                  * A simple interface call
7073                  *
7074                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7075                  * The imt slot contains a function descriptor for a runtime function + arg.
7076                  */
7077                 int slot_reg = alloc_preg (cfg);
7078                 int addr_reg = alloc_preg (cfg);
7079                 int arg_reg = alloc_preg (cfg);
7080                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7081
7082                 vtable_reg = alloc_preg (cfg);
7083                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7084                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7085
7086                 /*
7087                  * The slot is already initialized when the vtable is created so there is no need
7088                  * to check it here.
7089                  */
7090
7091                 /* Load the imt slot, which contains a function descriptor. */
7092                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7093
7094                 /* Load the address + arg of the imt thunk from the imt slot */
7095                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7096                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7097                 /*
7098                  * IMT thunks in llvm-only mode are C functions which take an info argument
7099                  * plus the imt method and return the ftndesc to call.
7100                  */
7101                 icall_args [0] = thunk_arg_ins;
7102                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7103                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7104                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7105
7106                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7107         }
7108
7109         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7110                 /*
7111                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7112                  * dynamically extended as more instantiations are discovered.
7113                  * This handles generic virtual methods both on classes and interfaces.
7114                  */
7115                 int slot_reg = alloc_preg (cfg);
7116                 int addr_reg = alloc_preg (cfg);
7117                 int arg_reg = alloc_preg (cfg);
7118                 int ftndesc_reg = alloc_preg (cfg);
7119                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7120                 MonoBasicBlock *slowpath_bb, *end_bb;
7121
7122                 NEW_BBLOCK (cfg, slowpath_bb);
7123                 NEW_BBLOCK (cfg, end_bb);
7124
7125                 vtable_reg = alloc_preg (cfg);
7126                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7127                 if (is_iface)
7128                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7129                 else
7130                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7131
7132                 /* Load the slot, which contains a function descriptor. */
7133                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7134
7135                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7136                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7137                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7138                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7139
7140                 /* Fastpath */
7141                 /* Same as with iface calls */
7142                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7143                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7144                 icall_args [0] = thunk_arg_ins;
7145                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7146                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7147                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7148                 ftndesc_ins->dreg = ftndesc_reg;
7149                 /*
7150                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7151                  * they don't know about yet. Fall back to the slowpath in that case.
7152                  */
7153                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7154                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7155
7156                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7157
7158                 /* Slowpath */
7159                 MONO_START_BB (cfg, slowpath_bb);
7160                 icall_args [0] = vtable_ins;
7161                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7162                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7163                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7164                 if (is_iface)
7165                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7166                 else
7167                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7168                 ftndesc_ins->dreg = ftndesc_reg;
7169                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7170
7171                 /* Common case */
7172                 MONO_START_BB (cfg, end_bb);
7173                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7174         }
7175
7176         /*
7177          * Non-optimized cases
7178          */
7179         icall_args [0] = sp [0];
7180         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7181
7182         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7183                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7184
7185         arg_reg = alloc_preg (cfg);
7186         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7187         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7188
7189         g_assert (is_gsharedvt);
7190         if (is_iface)
7191                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7192         else
7193                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7194
7195         /*
7196          * Pass the extra argument even if the callee doesn't receive it, most
7197          * calling conventions allow this.
7198          */
7199         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7200 }
7201
7202 static gboolean
7203 is_exception_class (MonoClass *klass)
7204 {
7205         while (klass) {
7206                 if (klass == mono_defaults.exception_class)
7207                         return TRUE;
7208                 klass = klass->parent;
7209         }
7210         return FALSE;
7211 }
7212
7213 /*
7214  * is_jit_optimizer_disabled:
7215  *
7216  *   Determine whenever M's assembly has a DebuggableAttribute with the
7217  * IsJITOptimizerDisabled flag set.
7218  */
7219 static gboolean
7220 is_jit_optimizer_disabled (MonoMethod *m)
7221 {
7222         MonoError error;
7223         MonoAssembly *ass = m->klass->image->assembly;
7224         MonoCustomAttrInfo* attrs;
7225         MonoClass *klass;
7226         int i;
7227         gboolean val = FALSE;
7228
7229         g_assert (ass);
7230         if (ass->jit_optimizer_disabled_inited)
7231                 return ass->jit_optimizer_disabled;
7232
7233         klass = mono_class_try_get_debuggable_attribute_class ();
7234
7235         if (!klass) {
7236                 /* Linked away */
7237                 ass->jit_optimizer_disabled = FALSE;
7238                 mono_memory_barrier ();
7239                 ass->jit_optimizer_disabled_inited = TRUE;
7240                 return FALSE;
7241         }
7242
7243         attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
7244         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7245         if (attrs) {
7246                 for (i = 0; i < attrs->num_attrs; ++i) {
7247                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7248                         const gchar *p;
7249                         MonoMethodSignature *sig;
7250
7251                         if (!attr->ctor || attr->ctor->klass != klass)
7252                                 continue;
7253                         /* Decode the attribute. See reflection.c */
7254                         p = (const char*)attr->data;
7255                         g_assert (read16 (p) == 0x0001);
7256                         p += 2;
7257
7258                         // FIXME: Support named parameters
7259                         sig = mono_method_signature (attr->ctor);
7260                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7261                                 continue;
7262                         /* Two boolean arguments */
7263                         p ++;
7264                         val = *p;
7265                 }
7266                 mono_custom_attrs_free (attrs);
7267         }
7268
7269         ass->jit_optimizer_disabled = val;
7270         mono_memory_barrier ();
7271         ass->jit_optimizer_disabled_inited = TRUE;
7272
7273         return val;
7274 }
7275
7276 static gboolean
7277 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7278 {
7279         gboolean supported_tail_call;
7280         int i;
7281
7282         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7283
7284         for (i = 0; i < fsig->param_count; ++i) {
7285                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7286                         /* These can point to the current method's stack */
7287                         supported_tail_call = FALSE;
7288         }
7289         if (fsig->hasthis && cmethod->klass->valuetype)
7290                 /* this might point to the current method's stack */
7291                 supported_tail_call = FALSE;
7292         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7293                 supported_tail_call = FALSE;
7294         if (cfg->method->save_lmf)
7295                 supported_tail_call = FALSE;
7296         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7297                 supported_tail_call = FALSE;
7298         if (call_opcode != CEE_CALL)
7299                 supported_tail_call = FALSE;
7300
7301         /* Debugging support */
7302 #if 0
7303         if (supported_tail_call) {
7304                 if (!mono_debug_count ())
7305                         supported_tail_call = FALSE;
7306         }
7307 #endif
7308
7309         return supported_tail_call;
7310 }
7311
7312 /*
7313  * handle_ctor_call:
7314  *
7315  *   Handle calls made to ctors from NEWOBJ opcodes.
7316  */
7317 static void
7318 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7319                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7320 {
7321         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7322
7323         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7324                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7325                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7326                         mono_class_vtable (cfg->domain, cmethod->klass);
7327                         CHECK_TYPELOAD (cmethod->klass);
7328
7329                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7330                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7331                 } else {
7332                         if (context_used) {
7333                                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
7334                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7335                         } else {
7336                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7337
7338                                 CHECK_TYPELOAD (cmethod->klass);
7339                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7340                         }
7341                 }
7342         }
7343
7344         /* Avoid virtual calls to ctors if possible */
7345         if (mono_class_is_marshalbyref (cmethod->klass))
7346                 callvirt_this_arg = sp [0];
7347
7348         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7349                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7350                 CHECK_CFG_EXCEPTION;
7351         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7352                            mono_method_check_inlining (cfg, cmethod) &&
7353                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7354                 int costs;
7355
7356                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7357                         cfg->real_offset += 5;
7358
7359                         *inline_costs += costs - 5;
7360                 } else {
7361                         INLINE_FAILURE ("inline failure");
7362                         // FIXME-VT: Clean this up
7363                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7364                                 GSHAREDVT_FAILURE(*ip);
7365                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7366                 }
7367         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7368                 MonoInst *addr;
7369
7370                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7371
7372                 if (cfg->llvm_only) {
7373                         // FIXME: Avoid initializing vtable_arg
7374                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7375                 } else {
7376                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7377                 }
7378         } else if (context_used &&
7379                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7380                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7381                 MonoInst *cmethod_addr;
7382
7383                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7384
7385                 if (cfg->llvm_only) {
7386                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
7387                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7388                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7389                 } else {
7390                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7391                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7392
7393                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7394                 }
7395         } else {
7396                 INLINE_FAILURE ("ctor call");
7397                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7398                                                                                   callvirt_this_arg, NULL, vtable_arg);
7399         }
7400  exception_exit:
7401         return;
7402 }
7403
7404 static void
7405 emit_setret (MonoCompile *cfg, MonoInst *val)
7406 {
7407         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7408         MonoInst *ins;
7409
7410         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7411                 MonoInst *ret_addr;
7412
7413                 if (!cfg->vret_addr) {
7414                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7415                 } else {
7416                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7417
7418                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7419                         ins->klass = mono_class_from_mono_type (ret_type);
7420                 }
7421         } else {
7422 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7423                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7424                         MonoInst *iargs [1];
7425                         MonoInst *conv;
7426
7427                         iargs [0] = val;
7428                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7429                         mono_arch_emit_setret (cfg, cfg->method, conv);
7430                 } else {
7431                         mono_arch_emit_setret (cfg, cfg->method, val);
7432                 }
7433 #else
7434                 mono_arch_emit_setret (cfg, cfg->method, val);
7435 #endif
7436         }
7437 }
7438
7439 /*
7440  * mono_method_to_ir:
7441  *
7442  * Translate the .net IL into linear IR.
7443  *
7444  * @start_bblock: if not NULL, the starting basic block, used during inlining.
7445  * @end_bblock: if not NULL, the ending basic block, used during inlining.
7446  * @return_var: if not NULL, the place where the return value is stored, used during inlining.   
7447  * @inline_args: if not NULL, contains the arguments to the inline call
7448  * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise.
7449  * @is_virtual_call: whether this method is being called as a result of a call to callvirt
7450  *
7451  * This method is used to turn ECMA IL into Mono's internal Linear IR
7452  * reprensetation.  It is used both for entire methods, as well as
7453  * inlining existing methods.  In the former case, the @start_bblock,
7454  * @end_bblock, @return_var, @inline_args are all set to NULL, and the
7455  * inline_offset is set to zero.
7456  * 
7457  * Returns: the inline cost, or -1 if there was an error processing this method.
7458  */
7459 int
7460 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7461                    MonoInst *return_var, MonoInst **inline_args, 
7462                    guint inline_offset, gboolean is_virtual_call)
7463 {
7464         MonoError error;
7465         MonoInst *ins, **sp, **stack_start;
7466         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7467         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7468         MonoMethod *cmethod, *method_definition;
7469         MonoInst **arg_array;
7470         MonoMethodHeader *header;
7471         MonoImage *image;
7472         guint32 token, ins_flag;
7473         MonoClass *klass;
7474         MonoClass *constrained_class = NULL;
7475         unsigned char *ip, *end, *target, *err_pos;
7476         MonoMethodSignature *sig;
7477         MonoGenericContext *generic_context = NULL;
7478         MonoGenericContainer *generic_container = NULL;
7479         MonoType **param_types;
7480         int i, n, start_new_bblock, dreg;
7481         int num_calls = 0, inline_costs = 0;
7482         int breakpoint_id = 0;
7483         guint num_args;
7484         GSList *class_inits = NULL;
7485         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7486         int context_used;
7487         gboolean init_locals, seq_points, skip_dead_blocks;
7488         gboolean sym_seq_points = FALSE;
7489         MonoDebugMethodInfo *minfo;
7490         MonoBitSet *seq_point_locs = NULL;
7491         MonoBitSet *seq_point_set_locs = NULL;
7492
7493         cfg->disable_inline = is_jit_optimizer_disabled (method);
7494
7495         /* serialization and xdomain stuff may need access to private fields and methods */
7496         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7497         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7498         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7499         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7500         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7501         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7502
7503         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7504         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7505         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7506         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7507         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7508
7509         image = method->klass->image;
7510         header = mono_method_get_header_checked (method, &cfg->error);
7511         if (!header) {
7512                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7513                 goto exception_exit;
7514         } else {
7515                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7516         }
7517
7518         generic_container = mono_method_get_generic_container (method);
7519         sig = mono_method_signature (method);
7520         num_args = sig->hasthis + sig->param_count;
7521         ip = (unsigned char*)header->code;
7522         cfg->cil_start = ip;
7523         end = ip + header->code_size;
7524         cfg->stat_cil_code_size += header->code_size;
7525
7526         seq_points = cfg->gen_seq_points && cfg->method == method;
7527
7528         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7529                 /* We could hit a seq point before attaching to the JIT (#8338) */
7530                 seq_points = FALSE;
7531         }
7532
7533         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7534                 minfo = mono_debug_lookup_method (method);
7535                 if (minfo) {
7536                         MonoSymSeqPoint *sps;
7537                         int i, n_il_offsets;
7538
7539                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7540                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7541                         seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7542                         sym_seq_points = TRUE;
7543                         for (i = 0; i < n_il_offsets; ++i) {
7544                                 if (sps [i].il_offset < header->code_size)
7545                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7546                         }
7547                         g_free (sps);
7548                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7549                         /* Methods without line number info like auto-generated property accessors */
7550                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7551                         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);
7552                         sym_seq_points = TRUE;
7553                 }
7554         }
7555
7556         /* 
7557          * Methods without init_locals set could cause asserts in various passes
7558          * (#497220). To work around this, we emit dummy initialization opcodes
7559          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7560          * on some platforms.
7561          */
7562         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
7563                 init_locals = header->init_locals;
7564         else
7565                 init_locals = TRUE;
7566
7567         method_definition = method;
7568         while (method_definition->is_inflated) {
7569                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7570                 method_definition = imethod->declaring;
7571         }
7572
7573         /* SkipVerification is not allowed if core-clr is enabled */
7574         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7575                 dont_verify = TRUE;
7576                 dont_verify_stloc = TRUE;
7577         }
7578
7579         if (sig->is_inflated)
7580                 generic_context = mono_method_get_context (method);
7581         else if (generic_container)
7582                 generic_context = &generic_container->context;
7583         cfg->generic_context = generic_context;
7584
7585         if (!cfg->gshared)
7586                 g_assert (!sig->has_type_parameters);
7587
7588         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7589                 g_assert (method->is_inflated);
7590                 g_assert (mono_method_get_context (method)->method_inst);
7591         }
7592         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7593                 g_assert (sig->generic_param_count);
7594
7595         if (cfg->method == method) {
7596                 cfg->real_offset = 0;
7597         } else {
7598                 cfg->real_offset = inline_offset;
7599         }
7600
7601         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7602         cfg->cil_offset_to_bb_len = header->code_size;
7603
7604         cfg->current_method = method;
7605
7606         if (cfg->verbose_level > 2)
7607                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7608
7609         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7610         if (sig->hasthis)
7611                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7612         for (n = 0; n < sig->param_count; ++n)
7613                 param_types [n + sig->hasthis] = sig->params [n];
7614         cfg->arg_types = param_types;
7615
7616         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7617         if (cfg->method == method) {
7618
7619                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7620                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7621
7622                 /* ENTRY BLOCK */
7623                 NEW_BBLOCK (cfg, start_bblock);
7624                 cfg->bb_entry = start_bblock;
7625                 start_bblock->cil_code = NULL;
7626                 start_bblock->cil_length = 0;
7627
7628                 /* EXIT BLOCK */
7629                 NEW_BBLOCK (cfg, end_bblock);
7630                 cfg->bb_exit = end_bblock;
7631                 end_bblock->cil_code = NULL;
7632                 end_bblock->cil_length = 0;
7633                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7634                 g_assert (cfg->num_bblocks == 2);
7635
7636                 arg_array = cfg->args;
7637
7638                 if (header->num_clauses) {
7639                         cfg->spvars = g_hash_table_new (NULL, NULL);
7640                         cfg->exvars = g_hash_table_new (NULL, NULL);
7641                 }
7642                 /* handle exception clauses */
7643                 for (i = 0; i < header->num_clauses; ++i) {
7644                         MonoBasicBlock *try_bb;
7645                         MonoExceptionClause *clause = &header->clauses [i];
7646                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7647
7648                         try_bb->real_offset = clause->try_offset;
7649                         try_bb->try_start = TRUE;
7650                         try_bb->region = ((i + 1) << 8) | clause->flags;
7651                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7652                         tblock->real_offset = clause->handler_offset;
7653                         tblock->flags |= BB_EXCEPTION_HANDLER;
7654
7655                         /*
7656                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7657                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7658                          */
7659                         if (COMPILE_LLVM (cfg))
7660                                 link_bblock (cfg, try_bb, tblock);
7661
7662                         if (*(ip + clause->handler_offset) == CEE_POP)
7663                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7664
7665                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7666                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7667                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7668                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7669                                 MONO_ADD_INS (tblock, ins);
7670
7671                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
7672                                         /* finally clauses already have a seq point */
7673                                         /* seq points for filter clauses are emitted below */
7674                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7675                                         MONO_ADD_INS (tblock, ins);
7676                                 }
7677
7678                                 /* todo: is a fault block unsafe to optimize? */
7679                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7680                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7681                         }
7682
7683                         /*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);
7684                           while (p < end) {
7685                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7686                           }*/
7687                         /* catch and filter blocks get the exception object on the stack */
7688                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7689                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7690
7691                                 /* mostly like handle_stack_args (), but just sets the input args */
7692                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7693                                 tblock->in_scount = 1;
7694                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7695                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7696
7697                                 cfg->cbb = tblock;
7698
7699 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7700                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7701                                 if (!cfg->compile_llvm) {
7702                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7703                                         ins->dreg = tblock->in_stack [0]->dreg;
7704                                         MONO_ADD_INS (tblock, ins);
7705                                 }
7706 #else
7707                                 MonoInst *dummy_use;
7708
7709                                 /* 
7710                                  * Add a dummy use for the exvar so its liveness info will be
7711                                  * correct.
7712                                  */
7713                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7714 #endif
7715
7716                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7717                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7718                                         MONO_ADD_INS (tblock, ins);
7719                                 }
7720                                 
7721                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7722                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7723                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7724                                         tblock->real_offset = clause->data.filter_offset;
7725                                         tblock->in_scount = 1;
7726                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7727                                         /* The filter block shares the exvar with the handler block */
7728                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7729                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7730                                         MONO_ADD_INS (tblock, ins);
7731                                 }
7732                         }
7733
7734                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7735                                         clause->data.catch_class &&
7736                                         cfg->gshared &&
7737                                         mono_class_check_context_used (clause->data.catch_class)) {
7738                                 /*
7739                                  * In shared generic code with catch
7740                                  * clauses containing type variables
7741                                  * the exception handling code has to
7742                                  * be able to get to the rgctx.
7743                                  * Therefore we have to make sure that
7744                                  * the vtable/mrgctx argument (for
7745                                  * static or generic methods) or the
7746                                  * "this" argument (for non-static
7747                                  * methods) are live.
7748                                  */
7749                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7750                                                 mini_method_get_context (method)->method_inst ||
7751                                                 method->klass->valuetype) {
7752                                         mono_get_vtable_var (cfg);
7753                                 } else {
7754                                         MonoInst *dummy_use;
7755
7756                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7757                                 }
7758                         }
7759                 }
7760         } else {
7761                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7762                 cfg->cbb = start_bblock;
7763                 cfg->args = arg_array;
7764                 mono_save_args (cfg, sig, inline_args);
7765         }
7766
7767         /* FIRST CODE BLOCK */
7768         NEW_BBLOCK (cfg, tblock);
7769         tblock->cil_code = ip;
7770         cfg->cbb = tblock;
7771         cfg->ip = ip;
7772
7773         ADD_BBLOCK (cfg, tblock);
7774
7775         if (cfg->method == method) {
7776                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7777                 if (breakpoint_id) {
7778                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7779                         MONO_ADD_INS (cfg->cbb, ins);
7780                 }
7781         }
7782
7783         /* we use a separate basic block for the initialization code */
7784         NEW_BBLOCK (cfg, init_localsbb);
7785         if (cfg->method == method)
7786                 cfg->bb_init = init_localsbb;
7787         init_localsbb->real_offset = cfg->real_offset;
7788         start_bblock->next_bb = init_localsbb;
7789         init_localsbb->next_bb = cfg->cbb;
7790         link_bblock (cfg, start_bblock, init_localsbb);
7791         link_bblock (cfg, init_localsbb, cfg->cbb);
7792                 
7793         cfg->cbb = init_localsbb;
7794
7795         if (cfg->gsharedvt && cfg->method == method) {
7796                 MonoGSharedVtMethodInfo *info;
7797                 MonoInst *var, *locals_var;
7798                 int dreg;
7799
7800                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7801                 info->method = cfg->method;
7802                 info->count_entries = 16;
7803                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7804                 cfg->gsharedvt_info = info;
7805
7806                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7807                 /* prevent it from being register allocated */
7808                 //var->flags |= MONO_INST_VOLATILE;
7809                 cfg->gsharedvt_info_var = var;
7810
7811                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7812                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7813
7814                 /* Allocate locals */
7815                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7816                 /* prevent it from being register allocated */
7817                 //locals_var->flags |= MONO_INST_VOLATILE;
7818                 cfg->gsharedvt_locals_var = locals_var;
7819
7820                 dreg = alloc_ireg (cfg);
7821                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7822
7823                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7824                 ins->dreg = locals_var->dreg;
7825                 ins->sreg1 = dreg;
7826                 MONO_ADD_INS (cfg->cbb, ins);
7827                 cfg->gsharedvt_locals_var_ins = ins;
7828                 
7829                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7830                 /*
7831                 if (init_locals)
7832                         ins->flags |= MONO_INST_INIT;
7833                 */
7834         }
7835
7836         if (mono_security_core_clr_enabled ()) {
7837                 /* check if this is native code, e.g. an icall or a p/invoke */
7838                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7839                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7840                         if (wrapped) {
7841                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7842                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7843
7844                                 /* if this ia a native call then it can only be JITted from platform code */
7845                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7846                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7847                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7848                                                         mono_get_exception_method_access ();
7849                                                 emit_throw_exception (cfg, ex);
7850                                         }
7851                                 }
7852                         }
7853                 }
7854         }
7855
7856         CHECK_CFG_EXCEPTION;
7857
7858         if (header->code_size == 0)
7859                 UNVERIFIED;
7860
7861         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7862                 ip = err_pos;
7863                 UNVERIFIED;
7864         }
7865
7866         if (cfg->method == method)
7867                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
7868
7869         for (n = 0; n < header->num_locals; ++n) {
7870                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7871                         UNVERIFIED;
7872         }
7873         class_inits = NULL;
7874
7875         /* We force the vtable variable here for all shared methods
7876            for the possibility that they might show up in a stack
7877            trace where their exact instantiation is needed. */
7878         if (cfg->gshared && method == cfg->method) {
7879                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7880                                 mini_method_get_context (method)->method_inst ||
7881                                 method->klass->valuetype) {
7882                         mono_get_vtable_var (cfg);
7883                 } else {
7884                         /* FIXME: Is there a better way to do this?
7885                            We need the variable live for the duration
7886                            of the whole method. */
7887                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7888                 }
7889         }
7890
7891         /* add a check for this != NULL to inlined methods */
7892         if (is_virtual_call) {
7893                 MonoInst *arg_ins;
7894
7895                 NEW_ARGLOAD (cfg, arg_ins, 0);
7896                 MONO_ADD_INS (cfg->cbb, arg_ins);
7897                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7898         }
7899
7900         skip_dead_blocks = !dont_verify;
7901         if (skip_dead_blocks) {
7902                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
7903                 CHECK_CFG_ERROR;
7904                 g_assert (bb);
7905         }
7906
7907         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7908         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7909
7910         ins_flag = 0;
7911         start_new_bblock = 0;
7912         while (ip < end) {
7913                 if (cfg->method == method)
7914                         cfg->real_offset = ip - header->code;
7915                 else
7916                         cfg->real_offset = inline_offset;
7917                 cfg->ip = ip;
7918
7919                 context_used = 0;
7920
7921                 if (start_new_bblock) {
7922                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
7923                         if (start_new_bblock == 2) {
7924                                 g_assert (ip == tblock->cil_code);
7925                         } else {
7926                                 GET_BBLOCK (cfg, tblock, ip);
7927                         }
7928                         cfg->cbb->next_bb = tblock;
7929                         cfg->cbb = tblock;
7930                         start_new_bblock = 0;
7931                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
7932                                 if (cfg->verbose_level > 3)
7933                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7934                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7935                                 *sp++ = ins;
7936                         }
7937                         if (class_inits)
7938                                 g_slist_free (class_inits);
7939                         class_inits = NULL;
7940                 } else {
7941                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
7942                                 link_bblock (cfg, cfg->cbb, tblock);
7943                                 if (sp != stack_start) {
7944                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7945                                         sp = stack_start;
7946                                         CHECK_UNVERIFIABLE (cfg);
7947                                 }
7948                                 cfg->cbb->next_bb = tblock;
7949                                 cfg->cbb = tblock;
7950                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
7951                                         if (cfg->verbose_level > 3)
7952                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7953                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7954                                         *sp++ = ins;
7955                                 }
7956                                 g_slist_free (class_inits);
7957                                 class_inits = NULL;
7958                         }
7959                 }
7960
7961                 if (skip_dead_blocks) {
7962                         int ip_offset = ip - header->code;
7963
7964                         if (ip_offset == bb->end)
7965                                 bb = bb->next;
7966
7967                         if (bb->dead) {
7968                                 int op_size = mono_opcode_size (ip, end);
7969                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7970
7971                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7972
7973                                 if (ip_offset + op_size == bb->end) {
7974                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7975                                         MONO_ADD_INS (cfg->cbb, ins);
7976                                         start_new_bblock = 1;
7977                                 }
7978
7979                                 ip += op_size;
7980                                 continue;
7981                         }
7982                 }
7983                 /*
7984                  * Sequence points are points where the debugger can place a breakpoint.
7985                  * Currently, we generate these automatically at points where the IL
7986                  * stack is empty.
7987                  */
7988                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7989                         /*
7990                          * Make methods interruptable at the beginning, and at the targets of
7991                          * backward branches.
7992                          * Also, do this at the start of every bblock in methods with clauses too,
7993                          * to be able to handle instructions with inprecise control flow like
7994                          * throw/endfinally.
7995                          * Backward branches are handled at the end of method-to-ir ().
7996                          */
7997                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7998                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
7999
8000                         /* Avoid sequence points on empty IL like .volatile */
8001                         // FIXME: Enable this
8002                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8003                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8004                         if ((sp != stack_start) && !sym_seq_point)
8005                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8006                         MONO_ADD_INS (cfg->cbb, ins);
8007
8008                         if (sym_seq_points)
8009                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8010                 }
8011
8012                 cfg->cbb->real_offset = cfg->real_offset;
8013
8014                 if ((cfg->method == method) && cfg->coverage_info) {
8015                         guint32 cil_offset = ip - header->code;
8016                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8017
8018                         /* TODO: Use an increment here */
8019 #if defined(TARGET_X86)
8020                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8021                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8022                         ins->inst_imm = 1;
8023                         MONO_ADD_INS (cfg->cbb, ins);
8024 #else
8025                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8026                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8027 #endif
8028                 }
8029
8030                 if (cfg->verbose_level > 3)
8031                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8032
8033                 switch (*ip) {
8034                 case CEE_NOP:
8035                         if (seq_points && !sym_seq_points && sp != stack_start) {
8036                                 /*
8037                                  * The C# compiler uses these nops to notify the JIT that it should
8038                                  * insert seq points.
8039                                  */
8040                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8041                                 MONO_ADD_INS (cfg->cbb, ins);
8042                         }
8043                         if (cfg->keep_cil_nops)
8044                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8045                         else
8046                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8047                         ip++;
8048                         MONO_ADD_INS (cfg->cbb, ins);
8049                         break;
8050                 case CEE_BREAK:
8051                         if (should_insert_brekpoint (cfg->method)) {
8052                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8053                         } else {
8054                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8055                         }
8056                         ip++;
8057                         MONO_ADD_INS (cfg->cbb, ins);
8058                         break;
8059                 case CEE_LDARG_0:
8060                 case CEE_LDARG_1:
8061                 case CEE_LDARG_2:
8062                 case CEE_LDARG_3:
8063                         CHECK_STACK_OVF (1);
8064                         n = (*ip)-CEE_LDARG_0;
8065                         CHECK_ARG (n);
8066                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8067                         ip++;
8068                         *sp++ = ins;
8069                         break;
8070                 case CEE_LDLOC_0:
8071                 case CEE_LDLOC_1:
8072                 case CEE_LDLOC_2:
8073                 case CEE_LDLOC_3:
8074                         CHECK_STACK_OVF (1);
8075                         n = (*ip)-CEE_LDLOC_0;
8076                         CHECK_LOCAL (n);
8077                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8078                         ip++;
8079                         *sp++ = ins;
8080                         break;
8081                 case CEE_STLOC_0:
8082                 case CEE_STLOC_1:
8083                 case CEE_STLOC_2:
8084                 case CEE_STLOC_3: {
8085                         CHECK_STACK (1);
8086                         n = (*ip)-CEE_STLOC_0;
8087                         CHECK_LOCAL (n);
8088                         --sp;
8089                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8090                                 UNVERIFIED;
8091                         emit_stloc_ir (cfg, sp, header, n);
8092                         ++ip;
8093                         inline_costs += 1;
8094                         break;
8095                         }
8096                 case CEE_LDARG_S:
8097                         CHECK_OPSIZE (2);
8098                         CHECK_STACK_OVF (1);
8099                         n = ip [1];
8100                         CHECK_ARG (n);
8101                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8102                         *sp++ = ins;
8103                         ip += 2;
8104                         break;
8105                 case CEE_LDARGA_S:
8106                         CHECK_OPSIZE (2);
8107                         CHECK_STACK_OVF (1);
8108                         n = ip [1];
8109                         CHECK_ARG (n);
8110                         NEW_ARGLOADA (cfg, ins, n);
8111                         MONO_ADD_INS (cfg->cbb, ins);
8112                         *sp++ = ins;
8113                         ip += 2;
8114                         break;
8115                 case CEE_STARG_S:
8116                         CHECK_OPSIZE (2);
8117                         CHECK_STACK (1);
8118                         --sp;
8119                         n = ip [1];
8120                         CHECK_ARG (n);
8121                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8122                                 UNVERIFIED;
8123                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8124                         ip += 2;
8125                         break;
8126                 case CEE_LDLOC_S:
8127                         CHECK_OPSIZE (2);
8128                         CHECK_STACK_OVF (1);
8129                         n = ip [1];
8130                         CHECK_LOCAL (n);
8131                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8132                         *sp++ = ins;
8133                         ip += 2;
8134                         break;
8135                 case CEE_LDLOCA_S: {
8136                         unsigned char *tmp_ip;
8137                         CHECK_OPSIZE (2);
8138                         CHECK_STACK_OVF (1);
8139                         CHECK_LOCAL (ip [1]);
8140
8141                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8142                                 ip = tmp_ip;
8143                                 inline_costs += 1;
8144                                 break;
8145                         }
8146
8147                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8148                         *sp++ = ins;
8149                         ip += 2;
8150                         break;
8151                 }
8152                 case CEE_STLOC_S:
8153                         CHECK_OPSIZE (2);
8154                         CHECK_STACK (1);
8155                         --sp;
8156                         CHECK_LOCAL (ip [1]);
8157                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8158                                 UNVERIFIED;
8159                         emit_stloc_ir (cfg, sp, header, ip [1]);
8160                         ip += 2;
8161                         inline_costs += 1;
8162                         break;
8163                 case CEE_LDNULL:
8164                         CHECK_STACK_OVF (1);
8165                         EMIT_NEW_PCONST (cfg, ins, NULL);
8166                         ins->type = STACK_OBJ;
8167                         ++ip;
8168                         *sp++ = ins;
8169                         break;
8170                 case CEE_LDC_I4_M1:
8171                         CHECK_STACK_OVF (1);
8172                         EMIT_NEW_ICONST (cfg, ins, -1);
8173                         ++ip;
8174                         *sp++ = ins;
8175                         break;
8176                 case CEE_LDC_I4_0:
8177                 case CEE_LDC_I4_1:
8178                 case CEE_LDC_I4_2:
8179                 case CEE_LDC_I4_3:
8180                 case CEE_LDC_I4_4:
8181                 case CEE_LDC_I4_5:
8182                 case CEE_LDC_I4_6:
8183                 case CEE_LDC_I4_7:
8184                 case CEE_LDC_I4_8:
8185                         CHECK_STACK_OVF (1);
8186                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8187                         ++ip;
8188                         *sp++ = ins;
8189                         break;
8190                 case CEE_LDC_I4_S:
8191                         CHECK_OPSIZE (2);
8192                         CHECK_STACK_OVF (1);
8193                         ++ip;
8194                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8195                         ++ip;
8196                         *sp++ = ins;
8197                         break;
8198                 case CEE_LDC_I4:
8199                         CHECK_OPSIZE (5);
8200                         CHECK_STACK_OVF (1);
8201                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8202                         ip += 5;
8203                         *sp++ = ins;
8204                         break;
8205                 case CEE_LDC_I8:
8206                         CHECK_OPSIZE (9);
8207                         CHECK_STACK_OVF (1);
8208                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8209                         ins->type = STACK_I8;
8210                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8211                         ++ip;
8212                         ins->inst_l = (gint64)read64 (ip);
8213                         MONO_ADD_INS (cfg->cbb, ins);
8214                         ip += 8;
8215                         *sp++ = ins;
8216                         break;
8217                 case CEE_LDC_R4: {
8218                         float *f;
8219                         gboolean use_aotconst = FALSE;
8220
8221 #ifdef TARGET_POWERPC
8222                         /* FIXME: Clean this up */
8223                         if (cfg->compile_aot)
8224                                 use_aotconst = TRUE;
8225 #endif
8226
8227                         /* FIXME: we should really allocate this only late in the compilation process */
8228                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8229                         CHECK_OPSIZE (5);
8230                         CHECK_STACK_OVF (1);
8231
8232                         if (use_aotconst) {
8233                                 MonoInst *cons;
8234                                 int dreg;
8235
8236                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8237
8238                                 dreg = alloc_freg (cfg);
8239                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8240                                 ins->type = cfg->r4_stack_type;
8241                         } else {
8242                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8243                                 ins->type = cfg->r4_stack_type;
8244                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8245                                 ins->inst_p0 = f;
8246                                 MONO_ADD_INS (cfg->cbb, ins);
8247                         }
8248                         ++ip;
8249                         readr4 (ip, f);
8250                         ip += 4;
8251                         *sp++ = ins;                    
8252                         break;
8253                 }
8254                 case CEE_LDC_R8: {
8255                         double *d;
8256                         gboolean use_aotconst = FALSE;
8257
8258 #ifdef TARGET_POWERPC
8259                         /* FIXME: Clean this up */
8260                         if (cfg->compile_aot)
8261                                 use_aotconst = TRUE;
8262 #endif
8263
8264                         /* FIXME: we should really allocate this only late in the compilation process */
8265                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8266                         CHECK_OPSIZE (9);
8267                         CHECK_STACK_OVF (1);
8268
8269                         if (use_aotconst) {
8270                                 MonoInst *cons;
8271                                 int dreg;
8272
8273                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8274
8275                                 dreg = alloc_freg (cfg);
8276                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8277                                 ins->type = STACK_R8;
8278                         } else {
8279                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8280                                 ins->type = STACK_R8;
8281                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8282                                 ins->inst_p0 = d;
8283                                 MONO_ADD_INS (cfg->cbb, ins);
8284                         }
8285                         ++ip;
8286                         readr8 (ip, d);
8287                         ip += 8;
8288                         *sp++ = ins;
8289                         break;
8290                 }
8291                 case CEE_DUP: {
8292                         MonoInst *temp, *store;
8293                         CHECK_STACK (1);
8294                         CHECK_STACK_OVF (1);
8295                         sp--;
8296                         ins = *sp;
8297
8298                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8299                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8300
8301                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8302                         *sp++ = ins;
8303
8304                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8305                         *sp++ = ins;
8306
8307                         ++ip;
8308                         inline_costs += 2;
8309                         break;
8310                 }
8311                 case CEE_POP:
8312                         CHECK_STACK (1);
8313                         ip++;
8314                         --sp;
8315
8316 #ifdef TARGET_X86
8317                         if (sp [0]->type == STACK_R8)
8318                                 /* we need to pop the value from the x86 FP stack */
8319                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8320 #endif
8321                         break;
8322                 case CEE_JMP: {
8323                         MonoCallInst *call;
8324                         MonoMethodSignature *fsig;
8325                         int i, n;
8326
8327                         INLINE_FAILURE ("jmp");
8328                         GSHAREDVT_FAILURE (*ip);
8329
8330                         CHECK_OPSIZE (5);
8331                         if (stack_start != sp)
8332                                 UNVERIFIED;
8333                         token = read32 (ip + 1);
8334                         /* FIXME: check the signature matches */
8335                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8336                         CHECK_CFG_ERROR;
8337  
8338                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8339                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8340
8341                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8342
8343                         fsig = mono_method_signature (cmethod);
8344                         n = fsig->param_count + fsig->hasthis;
8345                         if (cfg->llvm_only) {
8346                                 MonoInst **args;
8347
8348                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8349                                 for (i = 0; i < n; ++i)
8350                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8351                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8352                                 /*
8353                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8354                                  * have to emit a normal return since llvm expects it.
8355                                  */
8356                                 if (cfg->ret)
8357                                         emit_setret (cfg, ins);
8358                                 MONO_INST_NEW (cfg, ins, OP_BR);
8359                                 ins->inst_target_bb = end_bblock;
8360                                 MONO_ADD_INS (cfg->cbb, ins);
8361                                 link_bblock (cfg, cfg->cbb, end_bblock);
8362                                 ip += 5;
8363                                 break;
8364                         } else if (cfg->backend->have_op_tail_call) {
8365                                 /* Handle tail calls similarly to calls */
8366                                 DISABLE_AOT (cfg);
8367
8368                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8369                                 call->method = cmethod;
8370                                 call->tail_call = TRUE;
8371                                 call->signature = mono_method_signature (cmethod);
8372                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8373                                 call->inst.inst_p0 = cmethod;
8374                                 for (i = 0; i < n; ++i)
8375                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8376
8377                                 if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
8378                                         call->vret_var = cfg->vret_addr;
8379
8380                                 mono_arch_emit_call (cfg, call);
8381                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8382                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8383                         } else {
8384                                 for (i = 0; i < num_args; ++i)
8385                                         /* Prevent arguments from being optimized away */
8386                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8387
8388                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8389                                 ins = (MonoInst*)call;
8390                                 ins->inst_p0 = cmethod;
8391                                 MONO_ADD_INS (cfg->cbb, ins);
8392                         }
8393
8394                         ip += 5;
8395                         start_new_bblock = 1;
8396                         break;
8397                 }
8398                 case CEE_CALLI: {
8399                         MonoInst *addr;
8400                         MonoMethodSignature *fsig;
8401
8402                         CHECK_OPSIZE (5);
8403                         token = read32 (ip + 1);
8404
8405                         ins = NULL;
8406
8407                         //GSHAREDVT_FAILURE (*ip);
8408                         cmethod = NULL;
8409                         CHECK_STACK (1);
8410                         --sp;
8411                         addr = *sp;
8412                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
8413                         CHECK_CFG_ERROR;
8414
8415                         if (method->dynamic && fsig->pinvoke) {
8416                                 MonoInst *args [3];
8417
8418                                 /*
8419                                  * This is a call through a function pointer using a pinvoke
8420                                  * signature. Have to create a wrapper and call that instead.
8421                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8422                                  * instead based on the signature.
8423                                  */
8424                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8425                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8426                                 args [2] = addr;
8427                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8428                         }
8429
8430                         n = fsig->param_count + fsig->hasthis;
8431
8432                         CHECK_STACK (n);
8433
8434                         //g_assert (!virtual_ || fsig->hasthis);
8435
8436                         sp -= n;
8437
8438                         inline_costs += 10 * num_calls++;
8439
8440                         /*
8441                          * Making generic calls out of gsharedvt methods.
8442                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8443                          * patching gshared method addresses into a gsharedvt method.
8444                          */
8445                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8446                                 /*
8447                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8448                                  */
8449                                 MonoInst *callee = addr;
8450
8451                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8452                                         /* Not tested */
8453                                         GSHAREDVT_FAILURE (*ip);
8454
8455                                 if (cfg->llvm_only)
8456                                         // FIXME:
8457                                         GSHAREDVT_FAILURE (*ip);
8458
8459                                 addr = emit_get_rgctx_sig (cfg, context_used,
8460                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8461                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8462                                 goto calli_end;
8463                         }
8464
8465                         /* Prevent inlining of methods with indirect calls */
8466                         INLINE_FAILURE ("indirect call");
8467
8468                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8469                                 MonoJumpInfoType info_type;
8470                                 gpointer info_data;
8471
8472                                 /*
8473                                  * Instead of emitting an indirect call, emit a direct call
8474                                  * with the contents of the aotconst as the patch info.
8475                                  */
8476                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8477                                         info_type = (MonoJumpInfoType)addr->inst_c1;
8478                                         info_data = addr->inst_p0;
8479                                 } else {
8480                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
8481                                         info_data = addr->inst_right->inst_left;
8482                                 }
8483
8484                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
8485                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
8486                                         NULLIFY_INS (addr);
8487                                         goto calli_end;
8488                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8489                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8490                                         NULLIFY_INS (addr);
8491                                         goto calli_end;
8492                                 }
8493                         }
8494                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8495
8496                         calli_end:
8497
8498                         /* End of call, INS should contain the result of the call, if any */
8499
8500                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8501                                 g_assert (ins);
8502                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8503                         }
8504
8505                         CHECK_CFG_EXCEPTION;
8506
8507                         ip += 5;
8508                         ins_flag = 0;
8509                         constrained_class = NULL;
8510                         break;
8511                 }
8512                 case CEE_CALL:
8513                 case CEE_CALLVIRT: {
8514                         MonoInst *addr = NULL;
8515                         MonoMethodSignature *fsig = NULL;
8516                         int array_rank = 0;
8517                         int virtual_ = *ip == CEE_CALLVIRT;
8518                         gboolean pass_imt_from_rgctx = FALSE;
8519                         MonoInst *imt_arg = NULL;
8520                         MonoInst *keep_this_alive = NULL;
8521                         gboolean pass_vtable = FALSE;
8522                         gboolean pass_mrgctx = FALSE;
8523                         MonoInst *vtable_arg = NULL;
8524                         gboolean check_this = FALSE;
8525                         gboolean supported_tail_call = FALSE;
8526                         gboolean tail_call = FALSE;
8527                         gboolean need_seq_point = FALSE;
8528                         guint32 call_opcode = *ip;
8529                         gboolean emit_widen = TRUE;
8530                         gboolean push_res = TRUE;
8531                         gboolean skip_ret = FALSE;
8532                         gboolean delegate_invoke = FALSE;
8533                         gboolean direct_icall = FALSE;
8534                         gboolean constrained_partial_call = FALSE;
8535                         MonoMethod *cil_method;
8536
8537                         CHECK_OPSIZE (5);
8538                         token = read32 (ip + 1);
8539
8540                         ins = NULL;
8541
8542                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8543                         CHECK_CFG_ERROR;
8544
8545                         cil_method = cmethod;
8546                                 
8547                         if (constrained_class) {
8548                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8549                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8550                                                 g_assert (!cmethod->klass->valuetype);
8551                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8552                                                         constrained_partial_call = TRUE;
8553                                         }
8554                                 }
8555
8556                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8557                                         if (cfg->verbose_level > 2)
8558                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8559                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8560                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8561                                                   cfg->gshared)) {
8562                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8563                                                 CHECK_CFG_ERROR;
8564                                         }
8565                                 } else {
8566                                         if (cfg->verbose_level > 2)
8567                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8568
8569                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8570                                                 /* 
8571                                                  * This is needed since get_method_constrained can't find 
8572                                                  * the method in klass representing a type var.
8573                                                  * The type var is guaranteed to be a reference type in this
8574                                                  * case.
8575                                                  */
8576                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8577                                                         g_assert (!cmethod->klass->valuetype);
8578                                         } else {
8579                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8580                                                 CHECK_CFG_ERROR;
8581                                         }
8582                                 }
8583                         }
8584                                         
8585                         if (!dont_verify && !cfg->skip_visibility) {
8586                                 MonoMethod *target_method = cil_method;
8587                                 if (method->is_inflated) {
8588                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
8589                                         CHECK_CFG_ERROR;
8590                                 }
8591                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8592                                         !mono_method_can_access_method (method, cil_method))
8593                                         emit_method_access_failure (cfg, method, cil_method);
8594                         }
8595
8596                         if (mono_security_core_clr_enabled ())
8597                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8598
8599                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8600                                 /* MS.NET seems to silently convert this to a callvirt */
8601                                 virtual_ = 1;
8602
8603                         {
8604                                 /*
8605                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8606                                  * converts to a callvirt.
8607                                  *
8608                                  * tests/bug-515884.il is an example of this behavior
8609                                  */
8610                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8611                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8612                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8613                                         virtual_ = 1;
8614                         }
8615
8616                         if (!cmethod->klass->inited)
8617                                 if (!mono_class_init (cmethod->klass))
8618                                         TYPE_LOAD_ERROR (cmethod->klass);
8619
8620                         fsig = mono_method_signature (cmethod);
8621                         if (!fsig)
8622                                 LOAD_ERROR;
8623                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8624                                 mini_class_is_system_array (cmethod->klass)) {
8625                                 array_rank = cmethod->klass->rank;
8626                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8627                                 direct_icall = TRUE;
8628                         } else if (fsig->pinvoke) {
8629                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8630                                 fsig = mono_method_signature (wrapper);
8631                         } else if (constrained_class) {
8632                         } else {
8633                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8634                                 CHECK_CFG_ERROR;
8635                         }
8636
8637                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
8638                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
8639
8640                         /* See code below */
8641                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8642                                 MonoBasicBlock *tbb;
8643
8644                                 GET_BBLOCK (cfg, tbb, ip + 5);
8645                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8646                                         /*
8647                                          * We want to extend the try block to cover the call, but we can't do it if the
8648                                          * call is made directly since its followed by an exception check.
8649                                          */
8650                                         direct_icall = FALSE;
8651                                 }
8652                         }
8653
8654                         mono_save_token_info (cfg, image, token, cil_method);
8655
8656                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8657                                 need_seq_point = TRUE;
8658
8659                         /* Don't support calls made using type arguments for now */
8660                         /*
8661                           if (cfg->gsharedvt) {
8662                           if (mini_is_gsharedvt_signature (fsig))
8663                           GSHAREDVT_FAILURE (*ip);
8664                           }
8665                         */
8666
8667                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8668                                 g_assert_not_reached ();
8669
8670                         n = fsig->param_count + fsig->hasthis;
8671
8672                         if (!cfg->gshared && mono_class_is_gtd (cmethod->klass))
8673                                 UNVERIFIED;
8674
8675                         if (!cfg->gshared)
8676                                 g_assert (!mono_method_check_context_used (cmethod));
8677
8678                         CHECK_STACK (n);
8679
8680                         //g_assert (!virtual_ || fsig->hasthis);
8681
8682                         sp -= n;
8683
8684                         /*
8685                          * We have the `constrained.' prefix opcode.
8686                          */
8687                         if (constrained_class) {
8688                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8689                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8690                                                 /* The 'Own method' case below */
8691                                         } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) {
8692                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8693                                         } else {
8694                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8695                                                 CHECK_CFG_EXCEPTION;
8696                                                 g_assert (ins);
8697                                                 goto call_end;
8698                                         }
8699                                 }
8700
8701                                 if (constrained_partial_call) {
8702                                         gboolean need_box = TRUE;
8703
8704                                         /*
8705                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8706                                          * called method is not known at compile time either. The called method could end up being
8707                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8708                                          * to box the receiver.
8709                                          * A simple solution would be to box always and make a normal virtual call, but that would
8710                                          * be bad performance wise.
8711                                          */
8712                                         if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) {
8713                                                 /*
8714                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8715                                                  */
8716                                                 need_box = FALSE;
8717                                         }
8718
8719                                         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)) {
8720                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8721                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8722                                                 ins->klass = constrained_class;
8723                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8724                                                 CHECK_CFG_EXCEPTION;
8725                                         } else if (need_box) {
8726                                                 MonoInst *box_type;
8727                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8728                                                 MonoInst *nonbox_call;
8729
8730                                                 /*
8731                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8732                                                  * if needed.
8733                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8734                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8735                                                  */
8736                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8737
8738                                                 NEW_BBLOCK (cfg, is_ref_bb);
8739                                                 NEW_BBLOCK (cfg, end_bb);
8740
8741                                                 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);
8742                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
8743                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
8744
8745                                                 /* Non-ref case */
8746                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8747
8748                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8749
8750                                                 /* Ref case */
8751                                                 MONO_START_BB (cfg, is_ref_bb);
8752                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8753                                                 ins->klass = constrained_class;
8754                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8755                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8756
8757                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8758
8759                                                 MONO_START_BB (cfg, end_bb);
8760                                                 cfg->cbb = end_bb;
8761
8762                                                 nonbox_call->dreg = ins->dreg;
8763                                                 goto call_end;
8764                                         } else {
8765                                                 g_assert (mono_class_is_interface (cmethod->klass));
8766                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8767                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8768                                                 goto call_end;
8769                                         }
8770                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8771                                         /*
8772                                          * The type parameter is instantiated as a valuetype,
8773                                          * but that type doesn't override the method we're
8774                                          * calling, so we need to box `this'.
8775                                          */
8776                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8777                                         ins->klass = constrained_class;
8778                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8779                                         CHECK_CFG_EXCEPTION;
8780                                 } else if (!constrained_class->valuetype) {
8781                                         int dreg = alloc_ireg_ref (cfg);
8782
8783                                         /*
8784                                          * The type parameter is instantiated as a reference
8785                                          * type.  We have a managed pointer on the stack, so
8786                                          * we need to dereference it here.
8787                                          */
8788                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8789                                         ins->type = STACK_OBJ;
8790                                         sp [0] = ins;
8791                                 } else {
8792                                         if (cmethod->klass->valuetype) {
8793                                                 /* Own method */
8794                                         } else {
8795                                                 /* Interface method */
8796                                                 int ioffset, slot;
8797
8798                                                 mono_class_setup_vtable (constrained_class);
8799                                                 CHECK_TYPELOAD (constrained_class);
8800                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8801                                                 if (ioffset == -1)
8802                                                         TYPE_LOAD_ERROR (constrained_class);
8803                                                 slot = mono_method_get_vtable_slot (cmethod);
8804                                                 if (slot == -1)
8805                                                         TYPE_LOAD_ERROR (cmethod->klass);
8806                                                 cmethod = constrained_class->vtable [ioffset + slot];
8807
8808                                                 if (cmethod->klass == mono_defaults.enum_class) {
8809                                                         /* Enum implements some interfaces, so treat this as the first case */
8810                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8811                                                         ins->klass = constrained_class;
8812                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8813                                                         CHECK_CFG_EXCEPTION;
8814                                                 }
8815                                         }
8816                                         virtual_ = 0;
8817                                 }
8818                                 constrained_class = NULL;
8819                         }
8820
8821                         if (check_call_signature (cfg, fsig, sp))
8822                                 UNVERIFIED;
8823
8824                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8825                                 delegate_invoke = TRUE;
8826
8827                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8828                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8829                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8830                                         emit_widen = FALSE;
8831                                 }
8832
8833                                 goto call_end;
8834                         }
8835
8836                         /* 
8837                          * If the callee is a shared method, then its static cctor
8838                          * might not get called after the call was patched.
8839                          */
8840                         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)) {
8841                                 emit_class_init (cfg, cmethod->klass);
8842                                 CHECK_TYPELOAD (cmethod->klass);
8843                         }
8844
8845                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8846
8847                         if (cfg->gshared) {
8848                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8849
8850                                 context_used = mini_method_check_context_used (cfg, cmethod);
8851
8852                                 if (context_used && mono_class_is_interface (cmethod->klass)) {
8853                                         /* Generic method interface
8854                                            calls are resolved via a
8855                                            helper function and don't
8856                                            need an imt. */
8857                                         if (!cmethod_context || !cmethod_context->method_inst)
8858                                                 pass_imt_from_rgctx = TRUE;
8859                                 }
8860
8861                                 /*
8862                                  * If a shared method calls another
8863                                  * shared method then the caller must
8864                                  * have a generic sharing context
8865                                  * because the magic trampoline
8866                                  * requires it.  FIXME: We shouldn't
8867                                  * have to force the vtable/mrgctx
8868                                  * variable here.  Instead there
8869                                  * should be a flag in the cfg to
8870                                  * request a generic sharing context.
8871                                  */
8872                                 if (context_used &&
8873                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
8874                                         mono_get_vtable_var (cfg);
8875                         }
8876
8877                         if (pass_vtable) {
8878                                 if (context_used) {
8879                                         vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8880                                 } else {
8881                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8882
8883                                         CHECK_TYPELOAD (cmethod->klass);
8884                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8885                                 }
8886                         }
8887
8888                         if (pass_mrgctx) {
8889                                 g_assert (!vtable_arg);
8890
8891                                 if (!cfg->compile_aot) {
8892                                         /* 
8893                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8894                                          * for type load errors before.
8895                                          */
8896                                         mono_class_setup_vtable (cmethod->klass);
8897                                         CHECK_TYPELOAD (cmethod->klass);
8898                                 }
8899
8900                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8901
8902                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8903                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8904                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8905                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8906                                         if (virtual_)
8907                                                 check_this = TRUE;
8908                                         virtual_ = 0;
8909                                 }
8910                         }
8911
8912                         if (pass_imt_from_rgctx) {
8913                                 g_assert (!pass_vtable);
8914
8915                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8916                                         cmethod, MONO_RGCTX_INFO_METHOD);
8917                         }
8918
8919                         if (check_this)
8920                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8921
8922                         /* Calling virtual generic methods */
8923                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
8924                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8925                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8926                             fsig->generic_param_count && 
8927                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
8928                                 !cfg->llvm_only) {
8929                                 MonoInst *this_temp, *this_arg_temp, *store;
8930                                 MonoInst *iargs [4];
8931
8932                                 g_assert (fsig->is_inflated);
8933
8934                                 /* Prevent inlining of methods that contain indirect calls */
8935                                 INLINE_FAILURE ("virtual generic call");
8936
8937                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8938                                         GSHAREDVT_FAILURE (*ip);
8939
8940                                 if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
8941                                         g_assert (!imt_arg);
8942                                         if (!context_used)
8943                                                 g_assert (cmethod->is_inflated);
8944                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8945                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8946                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8947                                 } else {
8948                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8949                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8950                                         MONO_ADD_INS (cfg->cbb, store);
8951
8952                                         /* FIXME: This should be a managed pointer */
8953                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8954
8955                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8956                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8957                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8958                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8959                                         addr = mono_emit_jit_icall (cfg,
8960                                                                                                 mono_helper_compile_generic_method, iargs);
8961
8962                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8963
8964                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8965                                 }
8966
8967                                 goto call_end;
8968                         }
8969
8970                         /*
8971                          * Implement a workaround for the inherent races involved in locking:
8972                          * Monitor.Enter ()
8973                          * try {
8974                          * } finally {
8975                          *    Monitor.Exit ()
8976                          * }
8977                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8978                          * try block, the Exit () won't be executed, see:
8979                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8980                          * To work around this, we extend such try blocks to include the last x bytes
8981                          * of the Monitor.Enter () call.
8982                          */
8983                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8984                                 MonoBasicBlock *tbb;
8985
8986                                 GET_BBLOCK (cfg, tbb, ip + 5);
8987                                 /* 
8988                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
8989                                  * from Monitor.Enter like ArgumentNullException.
8990                                  */
8991                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8992                                         /* Mark this bblock as needing to be extended */
8993                                         tbb->extend_try_block = TRUE;
8994                                 }
8995                         }
8996
8997                         /* Conversion to a JIT intrinsic */
8998                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
8999                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9000                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9001                                         emit_widen = FALSE;
9002                                 }
9003                                 goto call_end;
9004                         }
9005                         CHECK_CFG_ERROR;
9006                         
9007                         /* Inlining */
9008                         if ((cfg->opt & MONO_OPT_INLINE) &&
9009                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9010                             mono_method_check_inlining (cfg, cmethod)) {
9011                                 int costs;
9012                                 gboolean always = FALSE;
9013
9014                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9015                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9016                                         /* Prevent inlining of methods that call wrappers */
9017                                         INLINE_FAILURE ("wrapper call");
9018                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9019                                         always = TRUE;
9020                                 }
9021
9022                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9023                                 if (costs) {
9024                                         cfg->real_offset += 5;
9025
9026                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9027                                                 /* *sp is already set by inline_method */
9028                                                 sp++;
9029                                                 push_res = FALSE;
9030                                         }
9031
9032                                         inline_costs += costs;
9033
9034                                         goto call_end;
9035                                 }
9036                         }
9037
9038                         /* Tail recursion elimination */
9039                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9040                                 gboolean has_vtargs = FALSE;
9041                                 int i;
9042
9043                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9044                                 INLINE_FAILURE ("tail call");
9045
9046                                 /* keep it simple */
9047                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9048                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9049                                                 has_vtargs = TRUE;
9050                                 }
9051
9052                                 if (!has_vtargs) {
9053                                         if (need_seq_point) {
9054                                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9055                                                 need_seq_point = FALSE;
9056                                         }
9057                                         for (i = 0; i < n; ++i)
9058                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9059                                         MONO_INST_NEW (cfg, ins, OP_BR);
9060                                         MONO_ADD_INS (cfg->cbb, ins);
9061                                         tblock = start_bblock->out_bb [0];
9062                                         link_bblock (cfg, cfg->cbb, tblock);
9063                                         ins->inst_target_bb = tblock;
9064                                         start_new_bblock = 1;
9065
9066                                         /* skip the CEE_RET, too */
9067                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9068                                                 skip_ret = TRUE;
9069                                         push_res = FALSE;
9070                                         goto call_end;
9071                                 }
9072                         }
9073
9074                         inline_costs += 10 * num_calls++;
9075
9076                         /*
9077                          * Synchronized wrappers.
9078                          * Its hard to determine where to replace a method with its synchronized
9079                          * wrapper without causing an infinite recursion. The current solution is
9080                          * to add the synchronized wrapper in the trampolines, and to
9081                          * change the called method to a dummy wrapper, and resolve that wrapper
9082                          * to the real method in mono_jit_compile_method ().
9083                          */
9084                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9085                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9086                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9087                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9088                         }
9089
9090                         /*
9091                          * Making generic calls out of gsharedvt methods.
9092                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9093                          * patching gshared method addresses into a gsharedvt method.
9094                          */
9095                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) &&
9096                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9097                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9098                                 MonoRgctxInfoType info_type;
9099
9100                                 if (virtual_) {
9101                                         //if (mono_class_is_interface (cmethod->klass))
9102                                                 //GSHAREDVT_FAILURE (*ip);
9103                                         // disable for possible remoting calls
9104                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9105                                                 GSHAREDVT_FAILURE (*ip);
9106                                         if (fsig->generic_param_count) {
9107                                                 /* virtual generic call */
9108                                                 g_assert (!imt_arg);
9109                                                 /* Same as the virtual generic case above */
9110                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9111                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9112                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9113                                                 vtable_arg = NULL;
9114                                         } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) {
9115                                                 /* This can happen when we call a fully instantiated iface method */
9116                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9117                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9118                                                 vtable_arg = NULL;
9119                                         }
9120                                 }
9121
9122                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9123                                         keep_this_alive = sp [0];
9124
9125                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9126                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9127                                 else
9128                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9129                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9130
9131                                 if (cfg->llvm_only) {
9132                                         // FIXME: Avoid initializing vtable_arg
9133                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9134                                 } else {
9135                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9136                                 }
9137                                 goto call_end;
9138                         }
9139
9140                         /* Generic sharing */
9141
9142                         /*
9143                          * Use this if the callee is gsharedvt sharable too, since
9144                          * at runtime we might find an instantiation so the call cannot
9145                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9146                          */
9147                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9148                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9149                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9150                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9151                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9152                                 INLINE_FAILURE ("gshared");
9153
9154                                 g_assert (cfg->gshared && cmethod);
9155                                 g_assert (!addr);
9156
9157                                 /*
9158                                  * We are compiling a call to a
9159                                  * generic method from shared code,
9160                                  * which means that we have to look up
9161                                  * the method in the rgctx and do an
9162                                  * indirect call.
9163                                  */
9164                                 if (fsig->hasthis)
9165                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9166
9167                                 if (cfg->llvm_only) {
9168                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9169                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9170                                         else
9171                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9172                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9173                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9174                                 } else {
9175                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9176                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9177                                 }
9178                                 goto call_end;
9179                         }
9180
9181                         /* Direct calls to icalls */
9182                         if (direct_icall) {
9183                                 MonoMethod *wrapper;
9184                                 int costs;
9185
9186                                 /* Inline the wrapper */
9187                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9188
9189                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9190                                 g_assert (costs > 0);
9191                                 cfg->real_offset += 5;
9192
9193                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9194                                         /* *sp is already set by inline_method */
9195                                         sp++;
9196                                         push_res = FALSE;
9197                                 }
9198
9199                                 inline_costs += costs;
9200
9201                                 goto call_end;
9202                         }
9203                                         
9204                         /* Array methods */
9205                         if (array_rank) {
9206                                 MonoInst *addr;
9207
9208                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9209                                         MonoInst *val = sp [fsig->param_count];
9210
9211                                         if (val->type == STACK_OBJ) {
9212                                                 MonoInst *iargs [2];
9213
9214                                                 iargs [0] = sp [0];
9215                                                 iargs [1] = val;
9216                                                 
9217                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9218                                         }
9219                                         
9220                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9221                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9222                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
9223                                                 emit_write_barrier (cfg, addr, val);
9224                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9225                                                 GSHAREDVT_FAILURE (*ip);
9226                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9227                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9228
9229                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9230                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9231                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9232                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9233                                         CHECK_TYPELOAD (cmethod->klass);
9234                                         
9235                                         readonly = FALSE;
9236                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9237                                         ins = addr;
9238                                 } else {
9239                                         g_assert_not_reached ();
9240                                 }
9241
9242                                 emit_widen = FALSE;
9243                                 goto call_end;
9244                         }
9245
9246                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9247                         if (ins)
9248                                 goto call_end;
9249
9250                         /* Tail prefix / tail call optimization */
9251
9252                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9253                         /* FIXME: runtime generic context pointer for jumps? */
9254                         /* FIXME: handle this for generic sharing eventually */
9255                         if ((ins_flag & MONO_INST_TAILCALL) &&
9256                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9257                                 supported_tail_call = TRUE;
9258
9259                         if (supported_tail_call) {
9260                                 MonoCallInst *call;
9261
9262                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9263                                 INLINE_FAILURE ("tail call");
9264
9265                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9266
9267                                 if (cfg->backend->have_op_tail_call) {
9268                                         /* Handle tail calls similarly to normal calls */
9269                                         tail_call = TRUE;
9270                                 } else {
9271                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9272
9273                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9274                                         call->tail_call = TRUE;
9275                                         call->method = cmethod;
9276                                         call->signature = mono_method_signature (cmethod);
9277
9278                                         /*
9279                                          * We implement tail calls by storing the actual arguments into the 
9280                                          * argument variables, then emitting a CEE_JMP.
9281                                          */
9282                                         for (i = 0; i < n; ++i) {
9283                                                 /* Prevent argument from being register allocated */
9284                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9285                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9286                                         }
9287                                         ins = (MonoInst*)call;
9288                                         ins->inst_p0 = cmethod;
9289                                         ins->inst_p1 = arg_array [0];
9290                                         MONO_ADD_INS (cfg->cbb, ins);
9291                                         link_bblock (cfg, cfg->cbb, end_bblock);
9292                                         start_new_bblock = 1;
9293
9294                                         // FIXME: Eliminate unreachable epilogs
9295
9296                                         /*
9297                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9298                                          * only reachable from this call.
9299                                          */
9300                                         GET_BBLOCK (cfg, tblock, ip + 5);
9301                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9302                                                 skip_ret = TRUE;
9303                                         push_res = FALSE;
9304
9305                                         goto call_end;
9306                                 }
9307                         }
9308
9309                         /*
9310                          * Virtual calls in llvm-only mode.
9311                          */
9312                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9313                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9314                                 goto call_end;
9315                         }
9316
9317                         /* Common call */
9318                         if (!(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
9319                                 INLINE_FAILURE ("call");
9320                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9321                                                                                           imt_arg, vtable_arg);
9322
9323                         if (tail_call && !cfg->llvm_only) {
9324                                 link_bblock (cfg, cfg->cbb, end_bblock);
9325                                 start_new_bblock = 1;
9326
9327                                 // FIXME: Eliminate unreachable epilogs
9328
9329                                 /*
9330                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9331                                  * only reachable from this call.
9332                                  */
9333                                 GET_BBLOCK (cfg, tblock, ip + 5);
9334                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9335                                         skip_ret = TRUE;
9336                                 push_res = FALSE;
9337                         }
9338
9339                         call_end:
9340
9341                         /* End of call, INS should contain the result of the call, if any */
9342
9343                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9344                                 g_assert (ins);
9345                                 if (emit_widen)
9346                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9347                                 else
9348                                         *sp++ = ins;
9349                         }
9350
9351                         if (keep_this_alive) {
9352                                 MonoInst *dummy_use;
9353
9354                                 /* See mono_emit_method_call_full () */
9355                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9356                         }
9357
9358                         if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
9359                                 /*
9360                                  * Clang can convert these calls to tail calls which screw up the stack
9361                                  * walk. This happens even when the -fno-optimize-sibling-calls
9362                                  * option is passed to clang.
9363                                  * Work around this by emitting a dummy call.
9364                                  */
9365                                 mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
9366                         }
9367
9368                         CHECK_CFG_EXCEPTION;
9369
9370                         ip += 5;
9371                         if (skip_ret) {
9372                                 g_assert (*ip == CEE_RET);
9373                                 ip += 1;
9374                         }
9375                         ins_flag = 0;
9376                         constrained_class = NULL;
9377                         if (need_seq_point)
9378                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9379                         break;
9380                 }
9381                 case CEE_RET:
9382                         if (cfg->method != method) {
9383                                 /* return from inlined method */
9384                                 /* 
9385                                  * If in_count == 0, that means the ret is unreachable due to
9386                                  * being preceeded by a throw. In that case, inline_method () will
9387                                  * handle setting the return value 
9388                                  * (test case: test_0_inline_throw ()).
9389                                  */
9390                                 if (return_var && cfg->cbb->in_count) {
9391                                         MonoType *ret_type = mono_method_signature (method)->ret;
9392
9393                                         MonoInst *store;
9394                                         CHECK_STACK (1);
9395                                         --sp;
9396
9397                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9398                                                 UNVERIFIED;
9399
9400                                         //g_assert (returnvar != -1);
9401                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9402                                         cfg->ret_var_set = TRUE;
9403                                 } 
9404                         } else {
9405                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9406
9407                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9408                                         emit_pop_lmf (cfg);
9409
9410                                 if (cfg->ret) {
9411                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9412
9413                                         if (seq_points && !sym_seq_points) {
9414                                                 /* 
9415                                                  * Place a seq point here too even through the IL stack is not
9416                                                  * empty, so a step over on
9417                                                  * call <FOO>
9418                                                  * ret
9419                                                  * will work correctly.
9420                                                  */
9421                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9422                                                 MONO_ADD_INS (cfg->cbb, ins);
9423                                         }
9424
9425                                         g_assert (!return_var);
9426                                         CHECK_STACK (1);
9427                                         --sp;
9428
9429                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9430                                                 UNVERIFIED;
9431
9432                                         emit_setret (cfg, *sp);
9433                                 }
9434                         }
9435                         if (sp != stack_start)
9436                                 UNVERIFIED;
9437                         MONO_INST_NEW (cfg, ins, OP_BR);
9438                         ip++;
9439                         ins->inst_target_bb = end_bblock;
9440                         MONO_ADD_INS (cfg->cbb, ins);
9441                         link_bblock (cfg, cfg->cbb, end_bblock);
9442                         start_new_bblock = 1;
9443                         break;
9444                 case CEE_BR_S:
9445                         CHECK_OPSIZE (2);
9446                         MONO_INST_NEW (cfg, ins, OP_BR);
9447                         ip++;
9448                         target = ip + 1 + (signed char)(*ip);
9449                         ++ip;
9450                         GET_BBLOCK (cfg, tblock, target);
9451                         link_bblock (cfg, cfg->cbb, tblock);
9452                         ins->inst_target_bb = tblock;
9453                         if (sp != stack_start) {
9454                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9455                                 sp = stack_start;
9456                                 CHECK_UNVERIFIABLE (cfg);
9457                         }
9458                         MONO_ADD_INS (cfg->cbb, ins);
9459                         start_new_bblock = 1;
9460                         inline_costs += BRANCH_COST;
9461                         break;
9462                 case CEE_BEQ_S:
9463                 case CEE_BGE_S:
9464                 case CEE_BGT_S:
9465                 case CEE_BLE_S:
9466                 case CEE_BLT_S:
9467                 case CEE_BNE_UN_S:
9468                 case CEE_BGE_UN_S:
9469                 case CEE_BGT_UN_S:
9470                 case CEE_BLE_UN_S:
9471                 case CEE_BLT_UN_S:
9472                         CHECK_OPSIZE (2);
9473                         CHECK_STACK (2);
9474                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9475                         ip++;
9476                         target = ip + 1 + *(signed char*)ip;
9477                         ip++;
9478
9479                         ADD_BINCOND (NULL);
9480
9481                         sp = stack_start;
9482                         inline_costs += BRANCH_COST;
9483                         break;
9484                 case CEE_BR:
9485                         CHECK_OPSIZE (5);
9486                         MONO_INST_NEW (cfg, ins, OP_BR);
9487                         ip++;
9488
9489                         target = ip + 4 + (gint32)read32(ip);
9490                         ip += 4;
9491                         GET_BBLOCK (cfg, tblock, target);
9492                         link_bblock (cfg, cfg->cbb, tblock);
9493                         ins->inst_target_bb = tblock;
9494                         if (sp != stack_start) {
9495                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9496                                 sp = stack_start;
9497                                 CHECK_UNVERIFIABLE (cfg);
9498                         }
9499
9500                         MONO_ADD_INS (cfg->cbb, ins);
9501
9502                         start_new_bblock = 1;
9503                         inline_costs += BRANCH_COST;
9504                         break;
9505                 case CEE_BRFALSE_S:
9506                 case CEE_BRTRUE_S:
9507                 case CEE_BRFALSE:
9508                 case CEE_BRTRUE: {
9509                         MonoInst *cmp;
9510                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9511                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9512                         guint32 opsize = is_short ? 1 : 4;
9513
9514                         CHECK_OPSIZE (opsize);
9515                         CHECK_STACK (1);
9516                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9517                                 UNVERIFIED;
9518                         ip ++;
9519                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9520                         ip += opsize;
9521
9522                         sp--;
9523
9524                         GET_BBLOCK (cfg, tblock, target);
9525                         link_bblock (cfg, cfg->cbb, tblock);
9526                         GET_BBLOCK (cfg, tblock, ip);
9527                         link_bblock (cfg, cfg->cbb, tblock);
9528
9529                         if (sp != stack_start) {
9530                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9531                                 CHECK_UNVERIFIABLE (cfg);
9532                         }
9533
9534                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9535                         cmp->sreg1 = sp [0]->dreg;
9536                         type_from_op (cfg, cmp, sp [0], NULL);
9537                         CHECK_TYPE (cmp);
9538
9539 #if SIZEOF_REGISTER == 4
9540                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9541                                 /* Convert it to OP_LCOMPARE */
9542                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9543                                 ins->type = STACK_I8;
9544                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9545                                 ins->inst_l = 0;
9546                                 MONO_ADD_INS (cfg->cbb, ins);
9547                                 cmp->opcode = OP_LCOMPARE;
9548                                 cmp->sreg2 = ins->dreg;
9549                         }
9550 #endif
9551                         MONO_ADD_INS (cfg->cbb, cmp);
9552
9553                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9554                         type_from_op (cfg, ins, sp [0], NULL);
9555                         MONO_ADD_INS (cfg->cbb, ins);
9556                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9557                         GET_BBLOCK (cfg, tblock, target);
9558                         ins->inst_true_bb = tblock;
9559                         GET_BBLOCK (cfg, tblock, ip);
9560                         ins->inst_false_bb = tblock;
9561                         start_new_bblock = 2;
9562
9563                         sp = stack_start;
9564                         inline_costs += BRANCH_COST;
9565                         break;
9566                 }
9567                 case CEE_BEQ:
9568                 case CEE_BGE:
9569                 case CEE_BGT:
9570                 case CEE_BLE:
9571                 case CEE_BLT:
9572                 case CEE_BNE_UN:
9573                 case CEE_BGE_UN:
9574                 case CEE_BGT_UN:
9575                 case CEE_BLE_UN:
9576                 case CEE_BLT_UN:
9577                         CHECK_OPSIZE (5);
9578                         CHECK_STACK (2);
9579                         MONO_INST_NEW (cfg, ins, *ip);
9580                         ip++;
9581                         target = ip + 4 + (gint32)read32(ip);
9582                         ip += 4;
9583
9584                         ADD_BINCOND (NULL);
9585
9586                         sp = stack_start;
9587                         inline_costs += BRANCH_COST;
9588                         break;
9589                 case CEE_SWITCH: {
9590                         MonoInst *src1;
9591                         MonoBasicBlock **targets;
9592                         MonoBasicBlock *default_bblock;
9593                         MonoJumpInfoBBTable *table;
9594                         int offset_reg = alloc_preg (cfg);
9595                         int target_reg = alloc_preg (cfg);
9596                         int table_reg = alloc_preg (cfg);
9597                         int sum_reg = alloc_preg (cfg);
9598                         gboolean use_op_switch;
9599
9600                         CHECK_OPSIZE (5);
9601                         CHECK_STACK (1);
9602                         n = read32 (ip + 1);
9603                         --sp;
9604                         src1 = sp [0];
9605                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9606                                 UNVERIFIED;
9607
9608                         ip += 5;
9609                         CHECK_OPSIZE (n * sizeof (guint32));
9610                         target = ip + n * sizeof (guint32);
9611
9612                         GET_BBLOCK (cfg, default_bblock, target);
9613                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9614
9615                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9616                         for (i = 0; i < n; ++i) {
9617                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9618                                 targets [i] = tblock;
9619                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9620                                 ip += 4;
9621                         }
9622
9623                         if (sp != stack_start) {
9624                                 /* 
9625                                  * Link the current bb with the targets as well, so handle_stack_args
9626                                  * will set their in_stack correctly.
9627                                  */
9628                                 link_bblock (cfg, cfg->cbb, default_bblock);
9629                                 for (i = 0; i < n; ++i)
9630                                         link_bblock (cfg, cfg->cbb, targets [i]);
9631
9632                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9633                                 sp = stack_start;
9634                                 CHECK_UNVERIFIABLE (cfg);
9635
9636                                 /* Undo the links */
9637                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9638                                 for (i = 0; i < n; ++i)
9639                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9640                         }
9641
9642                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9643                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9644
9645                         for (i = 0; i < n; ++i)
9646                                 link_bblock (cfg, cfg->cbb, targets [i]);
9647
9648                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9649                         table->table = targets;
9650                         table->table_size = n;
9651
9652                         use_op_switch = FALSE;
9653 #ifdef TARGET_ARM
9654                         /* ARM implements SWITCH statements differently */
9655                         /* FIXME: Make it use the generic implementation */
9656                         if (!cfg->compile_aot)
9657                                 use_op_switch = TRUE;
9658 #endif
9659
9660                         if (COMPILE_LLVM (cfg))
9661                                 use_op_switch = TRUE;
9662
9663                         cfg->cbb->has_jump_table = 1;
9664
9665                         if (use_op_switch) {
9666                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9667                                 ins->sreg1 = src1->dreg;
9668                                 ins->inst_p0 = table;
9669                                 ins->inst_many_bb = targets;
9670                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
9671                                 MONO_ADD_INS (cfg->cbb, ins);
9672                         } else {
9673                                 if (sizeof (gpointer) == 8)
9674                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9675                                 else
9676                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9677
9678 #if SIZEOF_REGISTER == 8
9679                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9680                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9681 #endif
9682
9683                                 if (cfg->compile_aot) {
9684                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9685                                 } else {
9686                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9687                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9688                                         ins->inst_p0 = table;
9689                                         ins->dreg = table_reg;
9690                                         MONO_ADD_INS (cfg->cbb, ins);
9691                                 }
9692
9693                                 /* FIXME: Use load_memindex */
9694                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9695                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9696                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9697                         }
9698                         start_new_bblock = 1;
9699                         inline_costs += (BRANCH_COST * 2);
9700                         break;
9701                 }
9702                 case CEE_LDIND_I1:
9703                 case CEE_LDIND_U1:
9704                 case CEE_LDIND_I2:
9705                 case CEE_LDIND_U2:
9706                 case CEE_LDIND_I4:
9707                 case CEE_LDIND_U4:
9708                 case CEE_LDIND_I8:
9709                 case CEE_LDIND_I:
9710                 case CEE_LDIND_R4:
9711                 case CEE_LDIND_R8:
9712                 case CEE_LDIND_REF:
9713                         CHECK_STACK (1);
9714                         --sp;
9715
9716                         switch (*ip) {
9717                         case CEE_LDIND_R4:
9718                         case CEE_LDIND_R8:
9719                                 dreg = alloc_freg (cfg);
9720                                 break;
9721                         case CEE_LDIND_I8:
9722                                 dreg = alloc_lreg (cfg);
9723                                 break;
9724                         case CEE_LDIND_REF:
9725                                 dreg = alloc_ireg_ref (cfg);
9726                                 break;
9727                         default:
9728                                 dreg = alloc_preg (cfg);
9729                         }
9730
9731                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9732                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9733                         if (*ip == CEE_LDIND_R4)
9734                                 ins->type = cfg->r4_stack_type;
9735                         ins->flags |= ins_flag;
9736                         MONO_ADD_INS (cfg->cbb, ins);
9737                         *sp++ = ins;
9738                         if (ins_flag & MONO_INST_VOLATILE) {
9739                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9740                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9741                         }
9742                         ins_flag = 0;
9743                         ++ip;
9744                         break;
9745                 case CEE_STIND_REF:
9746                 case CEE_STIND_I1:
9747                 case CEE_STIND_I2:
9748                 case CEE_STIND_I4:
9749                 case CEE_STIND_I8:
9750                 case CEE_STIND_R4:
9751                 case CEE_STIND_R8:
9752                 case CEE_STIND_I:
9753                         CHECK_STACK (2);
9754                         sp -= 2;
9755
9756                         if (ins_flag & MONO_INST_VOLATILE) {
9757                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9758                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9759                         }
9760
9761                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9762                         ins->flags |= ins_flag;
9763                         ins_flag = 0;
9764
9765                         MONO_ADD_INS (cfg->cbb, ins);
9766
9767                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
9768                                 emit_write_barrier (cfg, sp [0], sp [1]);
9769
9770                         inline_costs += 1;
9771                         ++ip;
9772                         break;
9773
9774                 case CEE_MUL:
9775                         CHECK_STACK (2);
9776
9777                         MONO_INST_NEW (cfg, ins, (*ip));
9778                         sp -= 2;
9779                         ins->sreg1 = sp [0]->dreg;
9780                         ins->sreg2 = sp [1]->dreg;
9781                         type_from_op (cfg, ins, sp [0], sp [1]);
9782                         CHECK_TYPE (ins);
9783                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9784
9785                         /* Use the immediate opcodes if possible */
9786                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9787                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9788                                 if (imm_opcode != -1) {
9789                                         ins->opcode = imm_opcode;
9790                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9791                                         ins->sreg2 = -1;
9792
9793                                         NULLIFY_INS (sp [1]);
9794                                 }
9795                         }
9796
9797                         MONO_ADD_INS ((cfg)->cbb, (ins));
9798
9799                         *sp++ = mono_decompose_opcode (cfg, ins);
9800                         ip++;
9801                         break;
9802                 case CEE_ADD:
9803                 case CEE_SUB:
9804                 case CEE_DIV:
9805                 case CEE_DIV_UN:
9806                 case CEE_REM:
9807                 case CEE_REM_UN:
9808                 case CEE_AND:
9809                 case CEE_OR:
9810                 case CEE_XOR:
9811                 case CEE_SHL:
9812                 case CEE_SHR:
9813                 case CEE_SHR_UN:
9814                         CHECK_STACK (2);
9815
9816                         MONO_INST_NEW (cfg, ins, (*ip));
9817                         sp -= 2;
9818                         ins->sreg1 = sp [0]->dreg;
9819                         ins->sreg2 = sp [1]->dreg;
9820                         type_from_op (cfg, ins, sp [0], sp [1]);
9821                         CHECK_TYPE (ins);
9822                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9823                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9824
9825                         /* FIXME: Pass opcode to is_inst_imm */
9826
9827                         /* Use the immediate opcodes if possible */
9828                         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)) {
9829                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9830                                 if (imm_opcode != -1) {
9831                                         ins->opcode = imm_opcode;
9832                                         if (sp [1]->opcode == OP_I8CONST) {
9833 #if SIZEOF_REGISTER == 8
9834                                                 ins->inst_imm = sp [1]->inst_l;
9835 #else
9836                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9837                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9838 #endif
9839                                         }
9840                                         else
9841                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9842                                         ins->sreg2 = -1;
9843
9844                                         /* Might be followed by an instruction added by add_widen_op */
9845                                         if (sp [1]->next == NULL)
9846                                                 NULLIFY_INS (sp [1]);
9847                                 }
9848                         }
9849                         MONO_ADD_INS ((cfg)->cbb, (ins));
9850
9851                         *sp++ = mono_decompose_opcode (cfg, ins);
9852                         ip++;
9853                         break;
9854                 case CEE_NEG:
9855                 case CEE_NOT:
9856                 case CEE_CONV_I1:
9857                 case CEE_CONV_I2:
9858                 case CEE_CONV_I4:
9859                 case CEE_CONV_R4:
9860                 case CEE_CONV_R8:
9861                 case CEE_CONV_U4:
9862                 case CEE_CONV_I8:
9863                 case CEE_CONV_U8:
9864                 case CEE_CONV_OVF_I8:
9865                 case CEE_CONV_OVF_U8:
9866                 case CEE_CONV_R_UN:
9867                         CHECK_STACK (1);
9868
9869                         /* Special case this earlier so we have long constants in the IR */
9870                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9871                                 int data = sp [-1]->inst_c0;
9872                                 sp [-1]->opcode = OP_I8CONST;
9873                                 sp [-1]->type = STACK_I8;
9874 #if SIZEOF_REGISTER == 8
9875                                 if ((*ip) == CEE_CONV_U8)
9876                                         sp [-1]->inst_c0 = (guint32)data;
9877                                 else
9878                                         sp [-1]->inst_c0 = data;
9879 #else
9880                                 sp [-1]->inst_ls_word = data;
9881                                 if ((*ip) == CEE_CONV_U8)
9882                                         sp [-1]->inst_ms_word = 0;
9883                                 else
9884                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9885 #endif
9886                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9887                         }
9888                         else {
9889                                 ADD_UNOP (*ip);
9890                         }
9891                         ip++;
9892                         break;
9893                 case CEE_CONV_OVF_I4:
9894                 case CEE_CONV_OVF_I1:
9895                 case CEE_CONV_OVF_I2:
9896                 case CEE_CONV_OVF_I:
9897                 case CEE_CONV_OVF_U:
9898                         CHECK_STACK (1);
9899
9900                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9901                                 ADD_UNOP (CEE_CONV_OVF_I8);
9902                                 ADD_UNOP (*ip);
9903                         } else {
9904                                 ADD_UNOP (*ip);
9905                         }
9906                         ip++;
9907                         break;
9908                 case CEE_CONV_OVF_U1:
9909                 case CEE_CONV_OVF_U2:
9910                 case CEE_CONV_OVF_U4:
9911                         CHECK_STACK (1);
9912
9913                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9914                                 ADD_UNOP (CEE_CONV_OVF_U8);
9915                                 ADD_UNOP (*ip);
9916                         } else {
9917                                 ADD_UNOP (*ip);
9918                         }
9919                         ip++;
9920                         break;
9921                 case CEE_CONV_OVF_I1_UN:
9922                 case CEE_CONV_OVF_I2_UN:
9923                 case CEE_CONV_OVF_I4_UN:
9924                 case CEE_CONV_OVF_I8_UN:
9925                 case CEE_CONV_OVF_U1_UN:
9926                 case CEE_CONV_OVF_U2_UN:
9927                 case CEE_CONV_OVF_U4_UN:
9928                 case CEE_CONV_OVF_U8_UN:
9929                 case CEE_CONV_OVF_I_UN:
9930                 case CEE_CONV_OVF_U_UN:
9931                 case CEE_CONV_U2:
9932                 case CEE_CONV_U1:
9933                 case CEE_CONV_I:
9934                 case CEE_CONV_U:
9935                         CHECK_STACK (1);
9936                         ADD_UNOP (*ip);
9937                         CHECK_CFG_EXCEPTION;
9938                         ip++;
9939                         break;
9940                 case CEE_ADD_OVF:
9941                 case CEE_ADD_OVF_UN:
9942                 case CEE_MUL_OVF:
9943                 case CEE_MUL_OVF_UN:
9944                 case CEE_SUB_OVF:
9945                 case CEE_SUB_OVF_UN:
9946                         CHECK_STACK (2);
9947                         ADD_BINOP (*ip);
9948                         ip++;
9949                         break;
9950                 case CEE_CPOBJ:
9951                         GSHAREDVT_FAILURE (*ip);
9952                         CHECK_OPSIZE (5);
9953                         CHECK_STACK (2);
9954                         token = read32 (ip + 1);
9955                         klass = mini_get_class (method, token, generic_context);
9956                         CHECK_TYPELOAD (klass);
9957                         sp -= 2;
9958                         if (generic_class_is_reference_type (cfg, klass)) {
9959                                 MonoInst *store, *load;
9960                                 int dreg = alloc_ireg_ref (cfg);
9961
9962                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9963                                 load->flags |= ins_flag;
9964                                 MONO_ADD_INS (cfg->cbb, load);
9965
9966                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9967                                 store->flags |= ins_flag;
9968                                 MONO_ADD_INS (cfg->cbb, store);
9969
9970                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9971                                         emit_write_barrier (cfg, sp [0], sp [1]);
9972                         } else {
9973                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9974                         }
9975                         ins_flag = 0;
9976                         ip += 5;
9977                         break;
9978                 case CEE_LDOBJ: {
9979                         int loc_index = -1;
9980                         int stloc_len = 0;
9981
9982                         CHECK_OPSIZE (5);
9983                         CHECK_STACK (1);
9984                         --sp;
9985                         token = read32 (ip + 1);
9986                         klass = mini_get_class (method, token, generic_context);
9987                         CHECK_TYPELOAD (klass);
9988
9989                         /* Optimize the common ldobj+stloc combination */
9990                         switch (ip [5]) {
9991                         case CEE_STLOC_S:
9992                                 loc_index = ip [6];
9993                                 stloc_len = 2;
9994                                 break;
9995                         case CEE_STLOC_0:
9996                         case CEE_STLOC_1:
9997                         case CEE_STLOC_2:
9998                         case CEE_STLOC_3:
9999                                 loc_index = ip [5] - CEE_STLOC_0;
10000                                 stloc_len = 1;
10001                                 break;
10002                         default:
10003                                 break;
10004                         }
10005
10006                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10007                                 CHECK_LOCAL (loc_index);
10008
10009                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10010                                 ins->dreg = cfg->locals [loc_index]->dreg;
10011                                 ins->flags |= ins_flag;
10012                                 ip += 5;
10013                                 ip += stloc_len;
10014                                 if (ins_flag & MONO_INST_VOLATILE) {
10015                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10016                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10017                                 }
10018                                 ins_flag = 0;
10019                                 break;
10020                         }
10021
10022                         /* Optimize the ldobj+stobj combination */
10023                         /* The reference case ends up being a load+store anyway */
10024                         /* Skip this if the operation is volatile. */
10025                         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)) {
10026                                 CHECK_STACK (1);
10027
10028                                 sp --;
10029
10030                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10031
10032                                 ip += 5 + 5;
10033                                 ins_flag = 0;
10034                                 break;
10035                         }
10036
10037                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10038                         ins->flags |= ins_flag;
10039                         *sp++ = ins;
10040
10041                         if (ins_flag & MONO_INST_VOLATILE) {
10042                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10043                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10044                         }
10045
10046                         ip += 5;
10047                         ins_flag = 0;
10048                         inline_costs += 1;
10049                         break;
10050                 }
10051                 case CEE_LDSTR:
10052                         CHECK_STACK_OVF (1);
10053                         CHECK_OPSIZE (5);
10054                         n = read32 (ip + 1);
10055
10056                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10057                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10058                                 ins->type = STACK_OBJ;
10059                                 *sp = ins;
10060                         }
10061                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10062                                 MonoInst *iargs [1];
10063                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10064
10065                                 if (cfg->compile_aot)
10066                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10067                                 else
10068                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10069                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10070                         } else {
10071                                 if (cfg->opt & MONO_OPT_SHARED) {
10072                                         MonoInst *iargs [3];
10073
10074                                         if (cfg->compile_aot) {
10075                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10076                                         }
10077                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10078                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10079                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10080                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10081                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10082                                         CHECK_CFG_ERROR;
10083                                 } else {
10084                                         if (cfg->cbb->out_of_line) {
10085                                                 MonoInst *iargs [2];
10086
10087                                                 if (image == mono_defaults.corlib) {
10088                                                         /* 
10089                                                          * Avoid relocations in AOT and save some space by using a 
10090                                                          * version of helper_ldstr specialized to mscorlib.
10091                                                          */
10092                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10093                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10094                                                 } else {
10095                                                         /* Avoid creating the string object */
10096                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10097                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10098                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10099                                                 }
10100                                         } 
10101                                         else
10102                                         if (cfg->compile_aot) {
10103                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10104                                                 *sp = ins;
10105                                                 MONO_ADD_INS (cfg->cbb, ins);
10106                                         } 
10107                                         else {
10108                                                 NEW_PCONST (cfg, ins, NULL);
10109                                                 ins->type = STACK_OBJ;
10110                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10111                                                 CHECK_CFG_ERROR;
10112                                                 
10113                                                 if (!ins->inst_p0)
10114                                                         OUT_OF_MEMORY_FAILURE;
10115
10116                                                 *sp = ins;
10117                                                 MONO_ADD_INS (cfg->cbb, ins);
10118                                         }
10119                                 }
10120                         }
10121
10122                         sp++;
10123                         ip += 5;
10124                         break;
10125                 case CEE_NEWOBJ: {
10126                         MonoInst *iargs [2];
10127                         MonoMethodSignature *fsig;
10128                         MonoInst this_ins;
10129                         MonoInst *alloc;
10130                         MonoInst *vtable_arg = NULL;
10131
10132                         CHECK_OPSIZE (5);
10133                         token = read32 (ip + 1);
10134                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10135                         CHECK_CFG_ERROR;
10136
10137                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10138                         CHECK_CFG_ERROR;
10139
10140                         mono_save_token_info (cfg, image, token, cmethod);
10141
10142                         if (!mono_class_init (cmethod->klass))
10143                                 TYPE_LOAD_ERROR (cmethod->klass);
10144
10145                         context_used = mini_method_check_context_used (cfg, cmethod);
10146
10147                         if (mono_security_core_clr_enabled ())
10148                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10149
10150                         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)) {
10151                                 emit_class_init (cfg, cmethod->klass);
10152                                 CHECK_TYPELOAD (cmethod->klass);
10153                         }
10154
10155                         /*
10156                         if (cfg->gsharedvt) {
10157                                 if (mini_is_gsharedvt_variable_signature (sig))
10158                                         GSHAREDVT_FAILURE (*ip);
10159                         }
10160                         */
10161
10162                         n = fsig->param_count;
10163                         CHECK_STACK (n);
10164
10165                         /* 
10166                          * Generate smaller code for the common newobj <exception> instruction in
10167                          * argument checking code.
10168                          */
10169                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10170                                 is_exception_class (cmethod->klass) && n <= 2 &&
10171                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10172                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10173                                 MonoInst *iargs [3];
10174
10175                                 sp -= n;
10176
10177                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10178                                 switch (n) {
10179                                 case 0:
10180                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10181                                         break;
10182                                 case 1:
10183                                         iargs [1] = sp [0];
10184                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10185                                         break;
10186                                 case 2:
10187                                         iargs [1] = sp [0];
10188                                         iargs [2] = sp [1];
10189                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10190                                         break;
10191                                 default:
10192                                         g_assert_not_reached ();
10193                                 }
10194
10195                                 ip += 5;
10196                                 inline_costs += 5;
10197                                 break;
10198                         }
10199
10200                         /* move the args to allow room for 'this' in the first position */
10201                         while (n--) {
10202                                 --sp;
10203                                 sp [1] = sp [0];
10204                         }
10205
10206                         /* check_call_signature () requires sp[0] to be set */
10207                         this_ins.type = STACK_OBJ;
10208                         sp [0] = &this_ins;
10209                         if (check_call_signature (cfg, fsig, sp))
10210                                 UNVERIFIED;
10211
10212                         iargs [0] = NULL;
10213
10214                         if (mini_class_is_system_array (cmethod->klass)) {
10215                                 *sp = emit_get_rgctx_method (cfg, context_used,
10216                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10217
10218                                 /* Avoid varargs in the common case */
10219                                 if (fsig->param_count == 1)
10220                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10221                                 else if (fsig->param_count == 2)
10222                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10223                                 else if (fsig->param_count == 3)
10224                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10225                                 else if (fsig->param_count == 4)
10226                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10227                                 else
10228                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10229                         } else if (cmethod->string_ctor) {
10230                                 g_assert (!context_used);
10231                                 g_assert (!vtable_arg);
10232                                 /* we simply pass a null pointer */
10233                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10234                                 /* now call the string ctor */
10235                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10236                         } else {
10237                                 if (cmethod->klass->valuetype) {
10238                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10239                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10240                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10241
10242                                         alloc = NULL;
10243
10244                                         /* 
10245                                          * The code generated by mini_emit_virtual_call () expects
10246                                          * iargs [0] to be a boxed instance, but luckily the vcall
10247                                          * will be transformed into a normal call there.
10248                                          */
10249                                 } else if (context_used) {
10250                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10251                                         *sp = alloc;
10252                                 } else {
10253                                         MonoVTable *vtable = NULL;
10254
10255                                         if (!cfg->compile_aot)
10256                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10257                                         CHECK_TYPELOAD (cmethod->klass);
10258
10259                                         /*
10260                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10261                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10262                                          * As a workaround, we call class cctors before allocating objects.
10263                                          */
10264                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10265                                                 emit_class_init (cfg, cmethod->klass);
10266                                                 if (cfg->verbose_level > 2)
10267                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10268                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10269                                         }
10270
10271                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10272                                         *sp = alloc;
10273                                 }
10274                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10275
10276                                 if (alloc)
10277                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10278
10279                                 /* Now call the actual ctor */
10280                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10281                                 CHECK_CFG_EXCEPTION;
10282                         }
10283
10284                         if (alloc == NULL) {
10285                                 /* Valuetype */
10286                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10287                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10288                                 *sp++= ins;
10289                         } else {
10290                                 *sp++ = alloc;
10291                         }
10292                         
10293                         ip += 5;
10294                         inline_costs += 5;
10295                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10296                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10297                         break;
10298                 }
10299                 case CEE_CASTCLASS:
10300                 case CEE_ISINST: {
10301                         CHECK_STACK (1);
10302                         --sp;
10303                         CHECK_OPSIZE (5);
10304                         token = read32 (ip + 1);
10305                         klass = mini_get_class (method, token, generic_context);
10306                         CHECK_TYPELOAD (klass);
10307                         if (sp [0]->type != STACK_OBJ)
10308                                 UNVERIFIED;
10309
10310                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
10311                         ins->dreg = alloc_preg (cfg);
10312                         ins->sreg1 = (*sp)->dreg;
10313                         ins->klass = klass;
10314                         ins->type = STACK_OBJ;
10315                         MONO_ADD_INS (cfg->cbb, ins);
10316
10317                         CHECK_CFG_EXCEPTION;
10318                         *sp++ = ins;
10319                         ip += 5;
10320
10321                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10322                         break;
10323                 }
10324                 case CEE_UNBOX_ANY: {
10325                         MonoInst *res, *addr;
10326
10327                         CHECK_STACK (1);
10328                         --sp;
10329                         CHECK_OPSIZE (5);
10330                         token = read32 (ip + 1);
10331                         klass = mini_get_class (method, token, generic_context);
10332                         CHECK_TYPELOAD (klass);
10333
10334                         mono_save_token_info (cfg, image, token, klass);
10335
10336                         context_used = mini_class_check_context_used (cfg, klass);
10337
10338                         if (mini_is_gsharedvt_klass (klass)) {
10339                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10340                                 inline_costs += 2;
10341                         } else if (generic_class_is_reference_type (cfg, klass)) {
10342                                 if (MONO_INS_IS_PCONST_NULL (*sp)) {
10343                                         EMIT_NEW_PCONST (cfg, res, NULL);
10344                                         res->type = STACK_OBJ;
10345                                 } else {
10346                                         MONO_INST_NEW (cfg, res, OP_CASTCLASS);
10347                                         res->dreg = alloc_preg (cfg);
10348                                         res->sreg1 = (*sp)->dreg;
10349                                         res->klass = klass;
10350                                         res->type = STACK_OBJ;
10351                                         MONO_ADD_INS (cfg->cbb, res);
10352                                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10353                                 }
10354                         } else if (mono_class_is_nullable (klass)) {
10355                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10356                         } else {
10357                                 addr = handle_unbox (cfg, klass, sp, context_used);
10358                                 /* LDOBJ */
10359                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10360                                 res = ins;
10361                                 inline_costs += 2;
10362                         }
10363
10364                         *sp ++ = res;
10365                         ip += 5;
10366                         break;
10367                 }
10368                 case CEE_BOX: {
10369                         MonoInst *val;
10370                         MonoClass *enum_class;
10371                         MonoMethod *has_flag;
10372
10373                         CHECK_STACK (1);
10374                         --sp;
10375                         val = *sp;
10376                         CHECK_OPSIZE (5);
10377                         token = read32 (ip + 1);
10378                         klass = mini_get_class (method, token, generic_context);
10379                         CHECK_TYPELOAD (klass);
10380
10381                         mono_save_token_info (cfg, image, token, klass);
10382
10383                         context_used = mini_class_check_context_used (cfg, klass);
10384
10385                         if (generic_class_is_reference_type (cfg, klass)) {
10386                                 *sp++ = val;
10387                                 ip += 5;
10388                                 break;
10389                         }
10390
10391                         if (klass == mono_defaults.void_class)
10392                                 UNVERIFIED;
10393                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10394                                 UNVERIFIED;
10395                         /* frequent check in generic code: box (struct), brtrue */
10396
10397                         /*
10398                          * Look for:
10399                          *
10400                          *   <push int/long ptr>
10401                          *   <push int/long>
10402                          *   box MyFlags
10403                          *   constrained. MyFlags
10404                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10405                          *
10406                          * If we find this sequence and the operand types on box and constrained
10407                          * are equal, we can emit a specialized instruction sequence instead of
10408                          * the very slow HasFlag () call.
10409                          */
10410                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10411                             /* Cheap checks first. */
10412                             ip + 5 + 6 + 5 < end &&
10413                             ip [5] == CEE_PREFIX1 &&
10414                             ip [6] == CEE_CONSTRAINED_ &&
10415                             ip [11] == CEE_CALLVIRT &&
10416                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10417                             mono_class_is_enum (klass) &&
10418                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10419                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10420                             has_flag->klass == mono_defaults.enum_class &&
10421                             !strcmp (has_flag->name, "HasFlag") &&
10422                             has_flag->signature->hasthis &&
10423                             has_flag->signature->param_count == 1) {
10424                                 CHECK_TYPELOAD (enum_class);
10425
10426                                 if (enum_class == klass) {
10427                                         MonoInst *enum_this, *enum_flag;
10428
10429                                         ip += 5 + 6 + 5;
10430                                         --sp;
10431
10432                                         enum_this = sp [0];
10433                                         enum_flag = sp [1];
10434
10435                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10436                                         break;
10437                                 }
10438                         }
10439
10440                         // FIXME: LLVM can't handle the inconsistent bb linking
10441                         if (!mono_class_is_nullable (klass) &&
10442                                 !mini_is_gsharedvt_klass (klass) &&
10443                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10444                                 (ip [5] == CEE_BRTRUE || 
10445                                  ip [5] == CEE_BRTRUE_S ||
10446                                  ip [5] == CEE_BRFALSE ||
10447                                  ip [5] == CEE_BRFALSE_S)) {
10448                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10449                                 int dreg;
10450                                 MonoBasicBlock *true_bb, *false_bb;
10451
10452                                 ip += 5;
10453
10454                                 if (cfg->verbose_level > 3) {
10455                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10456                                         printf ("<box+brtrue opt>\n");
10457                                 }
10458
10459                                 switch (*ip) {
10460                                 case CEE_BRTRUE_S:
10461                                 case CEE_BRFALSE_S:
10462                                         CHECK_OPSIZE (2);
10463                                         ip++;
10464                                         target = ip + 1 + (signed char)(*ip);
10465                                         ip++;
10466                                         break;
10467                                 case CEE_BRTRUE:
10468                                 case CEE_BRFALSE:
10469                                         CHECK_OPSIZE (5);
10470                                         ip++;
10471                                         target = ip + 4 + (gint)(read32 (ip));
10472                                         ip += 4;
10473                                         break;
10474                                 default:
10475                                         g_assert_not_reached ();
10476                                 }
10477
10478                                 /* 
10479                                  * We need to link both bblocks, since it is needed for handling stack
10480                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10481                                  * Branching to only one of them would lead to inconsistencies, so
10482                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10483                                  */
10484                                 GET_BBLOCK (cfg, true_bb, target);
10485                                 GET_BBLOCK (cfg, false_bb, ip);
10486
10487                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10488                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10489
10490                                 if (sp != stack_start) {
10491                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10492                                         sp = stack_start;
10493                                         CHECK_UNVERIFIABLE (cfg);
10494                                 }
10495
10496                                 if (COMPILE_LLVM (cfg)) {
10497                                         dreg = alloc_ireg (cfg);
10498                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10499                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10500
10501                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10502                                 } else {
10503                                         /* The JIT can't eliminate the iconst+compare */
10504                                         MONO_INST_NEW (cfg, ins, OP_BR);
10505                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10506                                         MONO_ADD_INS (cfg->cbb, ins);
10507                                 }
10508
10509                                 start_new_bblock = 1;
10510                                 break;
10511                         }
10512
10513                         *sp++ = handle_box (cfg, val, klass, context_used);
10514
10515                         CHECK_CFG_EXCEPTION;
10516                         ip += 5;
10517                         inline_costs += 1;
10518                         break;
10519                 }
10520                 case CEE_UNBOX: {
10521                         CHECK_STACK (1);
10522                         --sp;
10523                         CHECK_OPSIZE (5);
10524                         token = read32 (ip + 1);
10525                         klass = mini_get_class (method, token, generic_context);
10526                         CHECK_TYPELOAD (klass);
10527
10528                         mono_save_token_info (cfg, image, token, klass);
10529
10530                         context_used = mini_class_check_context_used (cfg, klass);
10531
10532                         if (mono_class_is_nullable (klass)) {
10533                                 MonoInst *val;
10534
10535                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10536                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10537
10538                                 *sp++= ins;
10539                         } else {
10540                                 ins = handle_unbox (cfg, klass, sp, context_used);
10541                                 *sp++ = ins;
10542                         }
10543                         ip += 5;
10544                         inline_costs += 2;
10545                         break;
10546                 }
10547                 case CEE_LDFLD:
10548                 case CEE_LDFLDA:
10549                 case CEE_STFLD:
10550                 case CEE_LDSFLD:
10551                 case CEE_LDSFLDA:
10552                 case CEE_STSFLD: {
10553                         MonoClassField *field;
10554 #ifndef DISABLE_REMOTING
10555                         int costs;
10556 #endif
10557                         guint foffset;
10558                         gboolean is_instance;
10559                         int op;
10560                         gpointer addr = NULL;
10561                         gboolean is_special_static;
10562                         MonoType *ftype;
10563                         MonoInst *store_val = NULL;
10564                         MonoInst *thread_ins;
10565
10566                         op = *ip;
10567                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10568                         if (is_instance) {
10569                                 if (op == CEE_STFLD) {
10570                                         CHECK_STACK (2);
10571                                         sp -= 2;
10572                                         store_val = sp [1];
10573                                 } else {
10574                                         CHECK_STACK (1);
10575                                         --sp;
10576                                 }
10577                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10578                                         UNVERIFIED;
10579                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10580                                         UNVERIFIED;
10581                         } else {
10582                                 if (op == CEE_STSFLD) {
10583                                         CHECK_STACK (1);
10584                                         sp--;
10585                                         store_val = sp [0];
10586                                 }
10587                         }
10588
10589                         CHECK_OPSIZE (5);
10590                         token = read32 (ip + 1);
10591                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10592                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
10593                                 klass = field->parent;
10594                         }
10595                         else {
10596                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10597                                 CHECK_CFG_ERROR;
10598                         }
10599                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10600                                 FIELD_ACCESS_FAILURE (method, field);
10601                         mono_class_init (klass);
10602
10603                         /* if the class is Critical then transparent code cannot access it's fields */
10604                         if (!is_instance && mono_security_core_clr_enabled ())
10605                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10606
10607                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10608                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10609                         if (mono_security_core_clr_enabled ())
10610                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10611                         */
10612
10613                         ftype = mono_field_get_type (field);
10614
10615                         /*
10616                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10617                          * the static case.
10618                          */
10619                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
10620                                 switch (op) {
10621                                 case CEE_LDFLD:
10622                                         op = CEE_LDSFLD;
10623                                         break;
10624                                 case CEE_STFLD:
10625                                         op = CEE_STSFLD;
10626                                         break;
10627                                 case CEE_LDFLDA:
10628                                         op = CEE_LDSFLDA;
10629                                         break;
10630                                 default:
10631                                         g_assert_not_reached ();
10632                                 }
10633                                 is_instance = FALSE;
10634                         }
10635
10636                         context_used = mini_class_check_context_used (cfg, klass);
10637
10638                         /* INSTANCE CASE */
10639
10640                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10641                         if (op == CEE_STFLD) {
10642                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10643                                         UNVERIFIED;
10644 #ifndef DISABLE_REMOTING
10645                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10646                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10647                                         MonoInst *iargs [5];
10648
10649                                         GSHAREDVT_FAILURE (op);
10650
10651                                         iargs [0] = sp [0];
10652                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10653                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10654                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10655                                                     field->offset);
10656                                         iargs [4] = sp [1];
10657
10658                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10659                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10660                                                                                            iargs, ip, cfg->real_offset, TRUE);
10661                                                 CHECK_CFG_EXCEPTION;
10662                                                 g_assert (costs > 0);
10663                                                       
10664                                                 cfg->real_offset += 5;
10665
10666                                                 inline_costs += costs;
10667                                         } else {
10668                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10669                                         }
10670                                 } else
10671 #endif
10672                                 {
10673                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
10674
10675                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10676
10677                                         if (ins_flag & MONO_INST_VOLATILE) {
10678                                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10679                                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10680                                         }
10681
10682                                         if (mini_is_gsharedvt_klass (klass)) {
10683                                                 MonoInst *offset_ins;
10684
10685                                                 context_used = mini_class_check_context_used (cfg, klass);
10686
10687                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10688                                                 /* The value is offset by 1 */
10689                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10690                                                 dreg = alloc_ireg_mp (cfg);
10691                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10692                                                 wbarrier_ptr_ins = ins;
10693                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10694                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10695                                         } else {
10696                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10697                                         }
10698                                         if (sp [0]->opcode != OP_LDADDR)
10699                                                 store->flags |= MONO_INST_FAULT;
10700
10701                                         if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
10702                                                 if (mini_is_gsharedvt_klass (klass)) {
10703                                                         g_assert (wbarrier_ptr_ins);
10704                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
10705                                                 } else {
10706                                                         /* insert call to write barrier */
10707                                                         MonoInst *ptr;
10708                                                         int dreg;
10709
10710                                                         dreg = alloc_ireg_mp (cfg);
10711                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10712                                                         emit_write_barrier (cfg, ptr, sp [1]);
10713                                                 }
10714                                         }
10715
10716                                         store->flags |= ins_flag;
10717                                 }
10718                                 ins_flag = 0;
10719                                 ip += 5;
10720                                 break;
10721                         }
10722
10723 #ifndef DISABLE_REMOTING
10724                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10725                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10726                                 MonoInst *iargs [4];
10727
10728                                 GSHAREDVT_FAILURE (op);
10729
10730                                 iargs [0] = sp [0];
10731                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10732                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10733                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10734                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10735                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10736                                                                                    iargs, ip, cfg->real_offset, TRUE);
10737                                         CHECK_CFG_EXCEPTION;
10738                                         g_assert (costs > 0);
10739                                                       
10740                                         cfg->real_offset += 5;
10741
10742                                         *sp++ = iargs [0];
10743
10744                                         inline_costs += costs;
10745                                 } else {
10746                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10747                                         *sp++ = ins;
10748                                 }
10749                         } else 
10750 #endif
10751                         if (is_instance) {
10752                                 if (sp [0]->type == STACK_VTYPE) {
10753                                         MonoInst *var;
10754
10755                                         /* Have to compute the address of the variable */
10756
10757                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10758                                         if (!var)
10759                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10760                                         else
10761                                                 g_assert (var->klass == klass);
10762                                         
10763                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10764                                         sp [0] = ins;
10765                                 }
10766
10767                                 if (op == CEE_LDFLDA) {
10768                                         if (sp [0]->type == STACK_OBJ) {
10769                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10770                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10771                                         }
10772
10773                                         dreg = alloc_ireg_mp (cfg);
10774
10775                                         if (mini_is_gsharedvt_klass (klass)) {
10776                                                 MonoInst *offset_ins;
10777
10778                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10779                                                 /* The value is offset by 1 */
10780                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10781                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10782                                         } else {
10783                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10784                                         }
10785                                         ins->klass = mono_class_from_mono_type (field->type);
10786                                         ins->type = STACK_MP;
10787                                         *sp++ = ins;
10788                                 } else {
10789                                         MonoInst *load;
10790
10791                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10792
10793                                         if (sp [0]->opcode == OP_LDADDR && klass->simd_type && cfg->opt & MONO_OPT_SIMD) {
10794                                                 ins = mono_emit_simd_field_load (cfg, field, sp [0]);
10795                                                 if (ins) {
10796                                                         *sp++ = ins;
10797                                                         ins_flag = 0;
10798                                                         ip += 5;
10799                                                         break;
10800                                                 }
10801                                         }
10802
10803                                         if (mini_is_gsharedvt_klass (klass)) {
10804                                                 MonoInst *offset_ins;
10805
10806                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10807                                                 /* The value is offset by 1 */
10808                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10809                                                 dreg = alloc_ireg_mp (cfg);
10810                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10811                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10812                                         } else {
10813                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10814                                         }
10815                                         load->flags |= ins_flag;
10816                                         if (sp [0]->opcode != OP_LDADDR)
10817                                                 load->flags |= MONO_INST_FAULT;
10818                                         *sp++ = load;
10819                                 }
10820                         }
10821
10822                         if (is_instance) {
10823                                 ins_flag = 0;
10824                                 ip += 5;
10825                                 break;
10826                         }
10827
10828                         /* STATIC CASE */
10829                         context_used = mini_class_check_context_used (cfg, klass);
10830
10831                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
10832                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
10833                                 CHECK_CFG_ERROR;
10834                         }
10835
10836                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10837                          * to be called here.
10838                          */
10839                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10840                                 mono_class_vtable (cfg->domain, klass);
10841                                 CHECK_TYPELOAD (klass);
10842                         }
10843                         mono_domain_lock (cfg->domain);
10844                         if (cfg->domain->special_static_fields)
10845                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10846                         mono_domain_unlock (cfg->domain);
10847
10848                         is_special_static = mono_class_field_is_special_static (field);
10849
10850                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10851                                 thread_ins = mono_create_tls_get (cfg, TLS_KEY_THREAD);
10852                         else
10853                                 thread_ins = NULL;
10854
10855                         /* Generate IR to compute the field address */
10856                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10857                                 /*
10858                                  * Fast access to TLS data
10859                                  * Inline version of get_thread_static_data () in
10860                                  * threads.c.
10861                                  */
10862                                 guint32 offset;
10863                                 int idx, static_data_reg, array_reg, dreg;
10864
10865                                 GSHAREDVT_FAILURE (op);
10866
10867                                 static_data_reg = alloc_ireg (cfg);
10868                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
10869
10870                                 if (cfg->compile_aot) {
10871                                         int offset_reg, offset2_reg, idx_reg;
10872
10873                                         /* For TLS variables, this will return the TLS offset */
10874                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10875                                         offset_reg = ins->dreg;
10876                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10877                                         idx_reg = alloc_ireg (cfg);
10878                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
10879                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10880                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10881                                         array_reg = alloc_ireg (cfg);
10882                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10883                                         offset2_reg = alloc_ireg (cfg);
10884                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
10885                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
10886                                         dreg = alloc_ireg (cfg);
10887                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10888                                 } else {
10889                                         offset = (gsize)addr & 0x7fffffff;
10890                                         idx = offset & 0x3f;
10891
10892                                         array_reg = alloc_ireg (cfg);
10893                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10894                                         dreg = alloc_ireg (cfg);
10895                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
10896                                 }
10897                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10898                                         (cfg->compile_aot && is_special_static) ||
10899                                         (context_used && is_special_static)) {
10900                                 MonoInst *iargs [2];
10901
10902                                 g_assert (field->parent);
10903                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10904                                 if (context_used) {
10905                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10906                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10907                                 } else {
10908                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10909                                 }
10910                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10911                         } else if (context_used) {
10912                                 MonoInst *static_data;
10913
10914                                 /*
10915                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10916                                         method->klass->name_space, method->klass->name, method->name,
10917                                         depth, field->offset);
10918                                 */
10919
10920                                 if (mono_class_needs_cctor_run (klass, method))
10921                                         emit_class_init (cfg, klass);
10922
10923                                 /*
10924                                  * The pointer we're computing here is
10925                                  *
10926                                  *   super_info.static_data + field->offset
10927                                  */
10928                                 static_data = mini_emit_get_rgctx_klass (cfg, context_used,
10929                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10930
10931                                 if (mini_is_gsharedvt_klass (klass)) {
10932                                         MonoInst *offset_ins;
10933
10934                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10935                                         /* The value is offset by 1 */
10936                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10937                                         dreg = alloc_ireg_mp (cfg);
10938                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10939                                 } else if (field->offset == 0) {
10940                                         ins = static_data;
10941                                 } else {
10942                                         int addr_reg = mono_alloc_preg (cfg);
10943                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10944                                 }
10945                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10946                                 MonoInst *iargs [2];
10947
10948                                 g_assert (field->parent);
10949                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10950                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10951                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10952                         } else {
10953                                 MonoVTable *vtable = NULL;
10954
10955                                 if (!cfg->compile_aot)
10956                                         vtable = mono_class_vtable (cfg->domain, klass);
10957                                 CHECK_TYPELOAD (klass);
10958
10959                                 if (!addr) {
10960                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10961                                                 if (!(g_slist_find (class_inits, klass))) {
10962                                                         emit_class_init (cfg, klass);
10963                                                         if (cfg->verbose_level > 2)
10964                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10965                                                         class_inits = g_slist_prepend (class_inits, klass);
10966                                                 }
10967                                         } else {
10968                                                 if (cfg->run_cctors) {
10969                                                         /* This makes so that inline cannot trigger */
10970                                                         /* .cctors: too many apps depend on them */
10971                                                         /* running with a specific order... */
10972                                                         g_assert (vtable);
10973                                                         if (! vtable->initialized)
10974                                                                 INLINE_FAILURE ("class init");
10975                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
10976                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
10977                                                                 goto exception_exit;
10978                                                         }
10979                                                 }
10980                                         }
10981                                         if (cfg->compile_aot)
10982                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10983                                         else {
10984                                                 g_assert (vtable);
10985                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10986                                                 g_assert (addr);
10987                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10988                                         }
10989                                 } else {
10990                                         MonoInst *iargs [1];
10991                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10992                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10993                                 }
10994                         }
10995
10996                         /* Generate IR to do the actual load/store operation */
10997
10998                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
10999                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11000                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11001                         }
11002
11003                         if (op == CEE_LDSFLDA) {
11004                                 ins->klass = mono_class_from_mono_type (ftype);
11005                                 ins->type = STACK_PTR;
11006                                 *sp++ = ins;
11007                         } else if (op == CEE_STSFLD) {
11008                                 MonoInst *store;
11009
11010                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11011                                 store->flags |= ins_flag;
11012                         } else {
11013                                 gboolean is_const = FALSE;
11014                                 MonoVTable *vtable = NULL;
11015                                 gpointer addr = NULL;
11016
11017                                 if (!context_used) {
11018                                         vtable = mono_class_vtable (cfg->domain, klass);
11019                                         CHECK_TYPELOAD (klass);
11020                                 }
11021                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11022                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11023                                         int ro_type = ftype->type;
11024                                         if (!addr)
11025                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11026                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11027                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11028                                         }
11029
11030                                         GSHAREDVT_FAILURE (op);
11031
11032                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11033                                         is_const = TRUE;
11034                                         switch (ro_type) {
11035                                         case MONO_TYPE_BOOLEAN:
11036                                         case MONO_TYPE_U1:
11037                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11038                                                 sp++;
11039                                                 break;
11040                                         case MONO_TYPE_I1:
11041                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11042                                                 sp++;
11043                                                 break;                                          
11044                                         case MONO_TYPE_CHAR:
11045                                         case MONO_TYPE_U2:
11046                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11047                                                 sp++;
11048                                                 break;
11049                                         case MONO_TYPE_I2:
11050                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11051                                                 sp++;
11052                                                 break;
11053                                                 break;
11054                                         case MONO_TYPE_I4:
11055                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11056                                                 sp++;
11057                                                 break;                                          
11058                                         case MONO_TYPE_U4:
11059                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11060                                                 sp++;
11061                                                 break;
11062                                         case MONO_TYPE_I:
11063                                         case MONO_TYPE_U:
11064                                         case MONO_TYPE_PTR:
11065                                         case MONO_TYPE_FNPTR:
11066                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11067                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11068                                                 sp++;
11069                                                 break;
11070                                         case MONO_TYPE_STRING:
11071                                         case MONO_TYPE_OBJECT:
11072                                         case MONO_TYPE_CLASS:
11073                                         case MONO_TYPE_SZARRAY:
11074                                         case MONO_TYPE_ARRAY:
11075                                                 if (!mono_gc_is_moving ()) {
11076                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11077                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11078                                                         sp++;
11079                                                 } else {
11080                                                         is_const = FALSE;
11081                                                 }
11082                                                 break;
11083                                         case MONO_TYPE_I8:
11084                                         case MONO_TYPE_U8:
11085                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11086                                                 sp++;
11087                                                 break;
11088                                         case MONO_TYPE_R4:
11089                                         case MONO_TYPE_R8:
11090                                         case MONO_TYPE_VALUETYPE:
11091                                         default:
11092                                                 is_const = FALSE;
11093                                                 break;
11094                                         }
11095                                 }
11096
11097                                 if (!is_const) {
11098                                         MonoInst *load;
11099
11100                                         CHECK_STACK_OVF (1);
11101
11102                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11103                                         load->flags |= ins_flag;
11104                                         ins_flag = 0;
11105                                         *sp++ = load;
11106                                 }
11107                         }
11108
11109                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11110                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11111                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11112                         }
11113
11114                         ins_flag = 0;
11115                         ip += 5;
11116                         break;
11117                 }
11118                 case CEE_STOBJ:
11119                         CHECK_STACK (2);
11120                         sp -= 2;
11121                         CHECK_OPSIZE (5);
11122                         token = read32 (ip + 1);
11123                         klass = mini_get_class (method, token, generic_context);
11124                         CHECK_TYPELOAD (klass);
11125                         if (ins_flag & MONO_INST_VOLATILE) {
11126                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11127                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11128                         }
11129                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11130                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11131                         ins->flags |= ins_flag;
11132                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11133                                 generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
11134                                 /* insert call to write barrier */
11135                                 emit_write_barrier (cfg, sp [0], sp [1]);
11136                         }
11137                         ins_flag = 0;
11138                         ip += 5;
11139                         inline_costs += 1;
11140                         break;
11141
11142                         /*
11143                          * Array opcodes
11144                          */
11145                 case CEE_NEWARR: {
11146                         MonoInst *len_ins;
11147                         const char *data_ptr;
11148                         int data_size = 0;
11149                         guint32 field_token;
11150
11151                         CHECK_STACK (1);
11152                         --sp;
11153
11154                         CHECK_OPSIZE (5);
11155                         token = read32 (ip + 1);
11156
11157                         klass = mini_get_class (method, token, generic_context);
11158                         CHECK_TYPELOAD (klass);
11159
11160                         context_used = mini_class_check_context_used (cfg, klass);
11161
11162                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11163                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11164                                 ins->sreg1 = sp [0]->dreg;
11165                                 ins->type = STACK_I4;
11166                                 ins->dreg = alloc_ireg (cfg);
11167                                 MONO_ADD_INS (cfg->cbb, ins);
11168                                 *sp = mono_decompose_opcode (cfg, ins);
11169                         }
11170
11171                         if (context_used) {
11172                                 MonoInst *args [3];
11173                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11174                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11175
11176                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11177
11178                                 /* vtable */
11179                                 args [0] = mini_emit_get_rgctx_klass (cfg, context_used,
11180                                         array_class, MONO_RGCTX_INFO_VTABLE);
11181                                 /* array len */
11182                                 args [1] = sp [0];
11183
11184                                 if (managed_alloc)
11185                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11186                                 else
11187                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11188                         } else {
11189                                 if (cfg->opt & MONO_OPT_SHARED) {
11190                                         /* Decompose now to avoid problems with references to the domainvar */
11191                                         MonoInst *iargs [3];
11192
11193                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11194                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11195                                         iargs [2] = sp [0];
11196
11197                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11198                                 } else {
11199                                         /* Decompose later since it is needed by abcrem */
11200                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11201                                         mono_class_vtable (cfg->domain, array_type);
11202                                         CHECK_TYPELOAD (array_type);
11203
11204                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11205                                         ins->dreg = alloc_ireg_ref (cfg);
11206                                         ins->sreg1 = sp [0]->dreg;
11207                                         ins->inst_newa_class = klass;
11208                                         ins->type = STACK_OBJ;
11209                                         ins->klass = array_type;
11210                                         MONO_ADD_INS (cfg->cbb, ins);
11211                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11212                                         cfg->cbb->has_array_access = TRUE;
11213
11214                                         /* Needed so mono_emit_load_get_addr () gets called */
11215                                         mono_get_got_var (cfg);
11216                                 }
11217                         }
11218
11219                         len_ins = sp [0];
11220                         ip += 5;
11221                         *sp++ = ins;
11222                         inline_costs += 1;
11223
11224                         /* 
11225                          * we inline/optimize the initialization sequence if possible.
11226                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11227                          * for small sizes open code the memcpy
11228                          * ensure the rva field is big enough
11229                          */
11230                         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))) {
11231                                 MonoMethod *memcpy_method = get_memcpy_method ();
11232                                 MonoInst *iargs [3];
11233                                 int add_reg = alloc_ireg_mp (cfg);
11234
11235                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11236                                 if (cfg->compile_aot) {
11237                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11238                                 } else {
11239                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11240                                 }
11241                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11242                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11243                                 ip += 11;
11244                         }
11245
11246                         break;
11247                 }
11248                 case CEE_LDLEN:
11249                         CHECK_STACK (1);
11250                         --sp;
11251                         if (sp [0]->type != STACK_OBJ)
11252                                 UNVERIFIED;
11253
11254                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11255                         ins->dreg = alloc_preg (cfg);
11256                         ins->sreg1 = sp [0]->dreg;
11257                         ins->type = STACK_I4;
11258                         /* This flag will be inherited by the decomposition */
11259                         ins->flags |= MONO_INST_FAULT;
11260                         MONO_ADD_INS (cfg->cbb, ins);
11261                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11262                         cfg->cbb->has_array_access = TRUE;
11263                         ip ++;
11264                         *sp++ = ins;
11265                         break;
11266                 case CEE_LDELEMA:
11267                         CHECK_STACK (2);
11268                         sp -= 2;
11269                         CHECK_OPSIZE (5);
11270                         if (sp [0]->type != STACK_OBJ)
11271                                 UNVERIFIED;
11272
11273                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11274
11275                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11276                         CHECK_TYPELOAD (klass);
11277                         /* we need to make sure that this array is exactly the type it needs
11278                          * to be for correctness. the wrappers are lax with their usage
11279                          * so we need to ignore them here
11280                          */
11281                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11282                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11283                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11284                                 CHECK_TYPELOAD (array_class);
11285                         }
11286
11287                         readonly = FALSE;
11288                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11289                         *sp++ = ins;
11290                         ip += 5;
11291                         break;
11292                 case CEE_LDELEM:
11293                 case CEE_LDELEM_I1:
11294                 case CEE_LDELEM_U1:
11295                 case CEE_LDELEM_I2:
11296                 case CEE_LDELEM_U2:
11297                 case CEE_LDELEM_I4:
11298                 case CEE_LDELEM_U4:
11299                 case CEE_LDELEM_I8:
11300                 case CEE_LDELEM_I:
11301                 case CEE_LDELEM_R4:
11302                 case CEE_LDELEM_R8:
11303                 case CEE_LDELEM_REF: {
11304                         MonoInst *addr;
11305
11306                         CHECK_STACK (2);
11307                         sp -= 2;
11308
11309                         if (*ip == CEE_LDELEM) {
11310                                 CHECK_OPSIZE (5);
11311                                 token = read32 (ip + 1);
11312                                 klass = mini_get_class (method, token, generic_context);
11313                                 CHECK_TYPELOAD (klass);
11314                                 mono_class_init (klass);
11315                         }
11316                         else
11317                                 klass = array_access_to_klass (*ip);
11318
11319                         if (sp [0]->type != STACK_OBJ)
11320                                 UNVERIFIED;
11321
11322                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11323
11324                         if (mini_is_gsharedvt_variable_klass (klass)) {
11325                                 // FIXME-VT: OP_ICONST optimization
11326                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11327                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11328                                 ins->opcode = OP_LOADV_MEMBASE;
11329                         } else if (sp [1]->opcode == OP_ICONST) {
11330                                 int array_reg = sp [0]->dreg;
11331                                 int index_reg = sp [1]->dreg;
11332                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11333
11334                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
11335                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
11336
11337                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11338                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11339                         } else {
11340                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11341                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11342                         }
11343                         *sp++ = ins;
11344                         if (*ip == CEE_LDELEM)
11345                                 ip += 5;
11346                         else
11347                                 ++ip;
11348                         break;
11349                 }
11350                 case CEE_STELEM_I:
11351                 case CEE_STELEM_I1:
11352                 case CEE_STELEM_I2:
11353                 case CEE_STELEM_I4:
11354                 case CEE_STELEM_I8:
11355                 case CEE_STELEM_R4:
11356                 case CEE_STELEM_R8:
11357                 case CEE_STELEM_REF:
11358                 case CEE_STELEM: {
11359                         CHECK_STACK (3);
11360                         sp -= 3;
11361
11362                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11363
11364                         if (*ip == CEE_STELEM) {
11365                                 CHECK_OPSIZE (5);
11366                                 token = read32 (ip + 1);
11367                                 klass = mini_get_class (method, token, generic_context);
11368                                 CHECK_TYPELOAD (klass);
11369                                 mono_class_init (klass);
11370                         }
11371                         else
11372                                 klass = array_access_to_klass (*ip);
11373
11374                         if (sp [0]->type != STACK_OBJ)
11375                                 UNVERIFIED;
11376
11377                         emit_array_store (cfg, klass, sp, TRUE);
11378
11379                         if (*ip == CEE_STELEM)
11380                                 ip += 5;
11381                         else
11382                                 ++ip;
11383                         inline_costs += 1;
11384                         break;
11385                 }
11386                 case CEE_CKFINITE: {
11387                         CHECK_STACK (1);
11388                         --sp;
11389
11390                         if (cfg->llvm_only) {
11391                                 MonoInst *iargs [1];
11392
11393                                 iargs [0] = sp [0];
11394                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11395                         } else  {
11396                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11397                                 ins->sreg1 = sp [0]->dreg;
11398                                 ins->dreg = alloc_freg (cfg);
11399                                 ins->type = STACK_R8;
11400                                 MONO_ADD_INS (cfg->cbb, ins);
11401
11402                                 *sp++ = mono_decompose_opcode (cfg, ins);
11403                         }
11404
11405                         ++ip;
11406                         break;
11407                 }
11408                 case CEE_REFANYVAL: {
11409                         MonoInst *src_var, *src;
11410
11411                         int klass_reg = alloc_preg (cfg);
11412                         int dreg = alloc_preg (cfg);
11413
11414                         GSHAREDVT_FAILURE (*ip);
11415
11416                         CHECK_STACK (1);
11417                         MONO_INST_NEW (cfg, ins, *ip);
11418                         --sp;
11419                         CHECK_OPSIZE (5);
11420                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11421                         CHECK_TYPELOAD (klass);
11422
11423                         context_used = mini_class_check_context_used (cfg, klass);
11424
11425                         // FIXME:
11426                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11427                         if (!src_var)
11428                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11429                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11430                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11431
11432                         if (context_used) {
11433                                 MonoInst *klass_ins;
11434
11435                                 klass_ins = mini_emit_get_rgctx_klass (cfg, context_used,
11436                                                 klass, MONO_RGCTX_INFO_KLASS);
11437
11438                                 // FIXME:
11439                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11440                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11441                         } else {
11442                                 mini_emit_class_check (cfg, klass_reg, klass);
11443                         }
11444                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11445                         ins->type = STACK_MP;
11446                         ins->klass = klass;
11447                         *sp++ = ins;
11448                         ip += 5;
11449                         break;
11450                 }
11451                 case CEE_MKREFANY: {
11452                         MonoInst *loc, *addr;
11453
11454                         GSHAREDVT_FAILURE (*ip);
11455
11456                         CHECK_STACK (1);
11457                         MONO_INST_NEW (cfg, ins, *ip);
11458                         --sp;
11459                         CHECK_OPSIZE (5);
11460                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11461                         CHECK_TYPELOAD (klass);
11462
11463                         context_used = mini_class_check_context_used (cfg, klass);
11464
11465                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11466                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11467
11468                         if (context_used) {
11469                                 MonoInst *const_ins;
11470                                 int type_reg = alloc_preg (cfg);
11471
11472                                 const_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11473                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11474                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11475                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11476                         } else {
11477                                 int const_reg = alloc_preg (cfg);
11478                                 int type_reg = alloc_preg (cfg);
11479
11480                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11481                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11482                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11483                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11484                         }
11485                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11486
11487                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11488                         ins->type = STACK_VTYPE;
11489                         ins->klass = mono_defaults.typed_reference_class;
11490                         *sp++ = ins;
11491                         ip += 5;
11492                         break;
11493                 }
11494                 case CEE_LDTOKEN: {
11495                         gpointer handle;
11496                         MonoClass *handle_class;
11497
11498                         CHECK_STACK_OVF (1);
11499
11500                         CHECK_OPSIZE (5);
11501                         n = read32 (ip + 1);
11502
11503                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11504                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11505                                 handle = mono_method_get_wrapper_data (method, n);
11506                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
11507                                 if (handle_class == mono_defaults.typehandle_class)
11508                                         handle = &((MonoClass*)handle)->byval_arg;
11509                         }
11510                         else {
11511                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11512                                 CHECK_CFG_ERROR;
11513                         }
11514                         if (!handle)
11515                                 LOAD_ERROR;
11516                         mono_class_init (handle_class);
11517                         if (cfg->gshared) {
11518                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11519                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11520                                         /* This case handles ldtoken
11521                                            of an open type, like for
11522                                            typeof(Gen<>). */
11523                                         context_used = 0;
11524                                 } else if (handle_class == mono_defaults.typehandle_class) {
11525                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
11526                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11527                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11528                                 else if (handle_class == mono_defaults.methodhandle_class)
11529                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
11530                                 else
11531                                         g_assert_not_reached ();
11532                         }
11533
11534                         if ((cfg->opt & MONO_OPT_SHARED) &&
11535                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11536                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11537                                 MonoInst *addr, *vtvar, *iargs [3];
11538                                 int method_context_used;
11539
11540                                 method_context_used = mini_method_check_context_used (cfg, method);
11541
11542                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11543
11544                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11545                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11546                                 if (method_context_used) {
11547                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11548                                                 method, MONO_RGCTX_INFO_METHOD);
11549                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11550                                 } else {
11551                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11552                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11553                                 }
11554                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11555
11556                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11557
11558                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11559                         } else {
11560                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11561                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11562                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11563                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11564                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11565                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
11566
11567                                         mono_class_init (tclass);
11568                                         if (context_used) {
11569                                                 ins = mini_emit_get_rgctx_klass (cfg, context_used,
11570                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11571                                         } else if (cfg->compile_aot) {
11572                                                 if (method->wrapper_type) {
11573                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11574                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11575                                                                 /* Special case for static synchronized wrappers */
11576                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11577                                                         } else {
11578                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11579                                                                 /* FIXME: n is not a normal token */
11580                                                                 DISABLE_AOT (cfg);
11581                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11582                                                         }
11583                                                 } else {
11584                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11585                                                 }
11586                                         } else {
11587                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
11588                                                 CHECK_CFG_ERROR;
11589                                                 EMIT_NEW_PCONST (cfg, ins, rt);
11590                                         }
11591                                         ins->type = STACK_OBJ;
11592                                         ins->klass = cmethod->klass;
11593                                         ip += 5;
11594                                 } else {
11595                                         MonoInst *addr, *vtvar;
11596
11597                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11598
11599                                         if (context_used) {
11600                                                 if (handle_class == mono_defaults.typehandle_class) {
11601                                                         ins = mini_emit_get_rgctx_klass (cfg, context_used,
11602                                                                         mono_class_from_mono_type ((MonoType *)handle),
11603                                                                         MONO_RGCTX_INFO_TYPE);
11604                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11605                                                         ins = emit_get_rgctx_method (cfg, context_used,
11606                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
11607                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11608                                                         ins = emit_get_rgctx_field (cfg, context_used,
11609                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
11610                                                 } else {
11611                                                         g_assert_not_reached ();
11612                                                 }
11613                                         } else if (cfg->compile_aot) {
11614                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11615                                         } else {
11616                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11617                                         }
11618                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11619                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11620                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11621                                 }
11622                         }
11623
11624                         *sp++ = ins;
11625                         ip += 5;
11626                         break;
11627                 }
11628                 case CEE_THROW:
11629                         CHECK_STACK (1);
11630                         if (sp [-1]->type != STACK_OBJ)
11631                                 UNVERIFIED;
11632
11633                         MONO_INST_NEW (cfg, ins, OP_THROW);
11634                         --sp;
11635                         ins->sreg1 = sp [0]->dreg;
11636                         ip++;
11637                         cfg->cbb->out_of_line = TRUE;
11638                         MONO_ADD_INS (cfg->cbb, ins);
11639                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11640                         MONO_ADD_INS (cfg->cbb, ins);
11641                         sp = stack_start;
11642                         
11643                         link_bblock (cfg, cfg->cbb, end_bblock);
11644                         start_new_bblock = 1;
11645                         /* This can complicate code generation for llvm since the return value might not be defined */
11646                         if (COMPILE_LLVM (cfg))
11647                                 INLINE_FAILURE ("throw");
11648                         break;
11649                 case CEE_ENDFINALLY:
11650                         if (!ip_in_finally_clause (cfg, ip - header->code))
11651                                 UNVERIFIED;
11652                         /* mono_save_seq_point_info () depends on this */
11653                         if (sp != stack_start)
11654                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11655                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11656                         MONO_ADD_INS (cfg->cbb, ins);
11657                         ip++;
11658                         start_new_bblock = 1;
11659
11660                         /*
11661                          * Control will leave the method so empty the stack, otherwise
11662                          * the next basic block will start with a nonempty stack.
11663                          */
11664                         while (sp != stack_start) {
11665                                 sp--;
11666                         }
11667                         break;
11668                 case CEE_LEAVE:
11669                 case CEE_LEAVE_S: {
11670                         GList *handlers;
11671
11672                         if (*ip == CEE_LEAVE) {
11673                                 CHECK_OPSIZE (5);
11674                                 target = ip + 5 + (gint32)read32(ip + 1);
11675                         } else {
11676                                 CHECK_OPSIZE (2);
11677                                 target = ip + 2 + (signed char)(ip [1]);
11678                         }
11679
11680                         /* empty the stack */
11681                         while (sp != stack_start) {
11682                                 sp--;
11683                         }
11684
11685                         /* 
11686                          * If this leave statement is in a catch block, check for a
11687                          * pending exception, and rethrow it if necessary.
11688                          * We avoid doing this in runtime invoke wrappers, since those are called
11689                          * by native code which excepts the wrapper to catch all exceptions.
11690                          */
11691                         for (i = 0; i < header->num_clauses; ++i) {
11692                                 MonoExceptionClause *clause = &header->clauses [i];
11693
11694                                 /* 
11695                                  * Use <= in the final comparison to handle clauses with multiple
11696                                  * leave statements, like in bug #78024.
11697                                  * The ordering of the exception clauses guarantees that we find the
11698                                  * innermost clause.
11699                                  */
11700                                 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) {
11701                                         MonoInst *exc_ins;
11702                                         MonoBasicBlock *dont_throw;
11703
11704                                         /*
11705                                           MonoInst *load;
11706
11707                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11708                                         */
11709
11710                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11711
11712                                         NEW_BBLOCK (cfg, dont_throw);
11713
11714                                         /*
11715                                          * Currently, we always rethrow the abort exception, despite the 
11716                                          * fact that this is not correct. See thread6.cs for an example. 
11717                                          * But propagating the abort exception is more important than 
11718                                          * getting the sematics right.
11719                                          */
11720                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11721                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11722                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11723
11724                                         MONO_START_BB (cfg, dont_throw);
11725                                 }
11726                         }
11727
11728 #ifdef ENABLE_LLVM
11729                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
11730 #endif
11731
11732                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11733                                 GList *tmp;
11734                                 MonoExceptionClause *clause;
11735
11736                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11737                                         clause = (MonoExceptionClause *)tmp->data;
11738                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11739                                         g_assert (tblock);
11740                                         link_bblock (cfg, cfg->cbb, tblock);
11741                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11742                                         ins->inst_target_bb = tblock;
11743                                         ins->inst_eh_block = clause;
11744                                         MONO_ADD_INS (cfg->cbb, ins);
11745                                         cfg->cbb->has_call_handler = 1;
11746                                         if (COMPILE_LLVM (cfg)) {
11747                                                 MonoBasicBlock *target_bb;
11748
11749                                                 /* 
11750                                                  * Link the finally bblock with the target, since it will
11751                                                  * conceptually branch there.
11752                                                  */
11753                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
11754                                                 GET_BBLOCK (cfg, target_bb, target);
11755                                                 link_bblock (cfg, tblock, target_bb);
11756                                         }
11757                                 }
11758                                 g_list_free (handlers);
11759                         } 
11760
11761                         MONO_INST_NEW (cfg, ins, OP_BR);
11762                         MONO_ADD_INS (cfg->cbb, ins);
11763                         GET_BBLOCK (cfg, tblock, target);
11764                         link_bblock (cfg, cfg->cbb, tblock);
11765                         ins->inst_target_bb = tblock;
11766
11767                         start_new_bblock = 1;
11768
11769                         if (*ip == CEE_LEAVE)
11770                                 ip += 5;
11771                         else
11772                                 ip += 2;
11773
11774                         break;
11775                 }
11776
11777                         /*
11778                          * Mono specific opcodes
11779                          */
11780                 case MONO_CUSTOM_PREFIX: {
11781
11782                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11783
11784                         CHECK_OPSIZE (2);
11785                         switch (ip [1]) {
11786                         case CEE_MONO_ICALL: {
11787                                 gpointer func;
11788                                 MonoJitICallInfo *info;
11789
11790                                 token = read32 (ip + 2);
11791                                 func = mono_method_get_wrapper_data (method, token);
11792                                 info = mono_find_jit_icall_by_addr (func);
11793                                 if (!info)
11794                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11795                                 g_assert (info);
11796
11797                                 CHECK_STACK (info->sig->param_count);
11798                                 sp -= info->sig->param_count;
11799
11800                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11801                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11802                                         *sp++ = ins;
11803
11804                                 ip += 6;
11805                                 inline_costs += 10 * num_calls++;
11806
11807                                 break;
11808                         }
11809                         case CEE_MONO_LDPTR_CARD_TABLE:
11810                         case CEE_MONO_LDPTR_NURSERY_START:
11811                         case CEE_MONO_LDPTR_NURSERY_BITS:
11812                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
11813                                 CHECK_STACK_OVF (1);
11814
11815                                 switch (ip [1]) {
11816                                         case CEE_MONO_LDPTR_CARD_TABLE:
11817                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
11818                                                 break;
11819                                         case CEE_MONO_LDPTR_NURSERY_START:
11820                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
11821                                                 break;
11822                                         case CEE_MONO_LDPTR_NURSERY_BITS:
11823                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
11824                                                 break;
11825                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
11826                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11827                                                 break;
11828                                 }
11829
11830                                 *sp++ = ins;
11831                                 ip += 2;
11832                                 inline_costs += 10 * num_calls++;
11833                                 break;
11834                         }
11835                         case CEE_MONO_LDPTR: {
11836                                 gpointer ptr;
11837
11838                                 CHECK_STACK_OVF (1);
11839                                 CHECK_OPSIZE (6);
11840                                 token = read32 (ip + 2);
11841
11842                                 ptr = mono_method_get_wrapper_data (method, token);
11843                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11844                                 *sp++ = ins;
11845                                 ip += 6;
11846                                 inline_costs += 10 * num_calls++;
11847                                 /* Can't embed random pointers into AOT code */
11848                                 DISABLE_AOT (cfg);
11849                                 break;
11850                         }
11851                         case CEE_MONO_JIT_ICALL_ADDR: {
11852                                 MonoJitICallInfo *callinfo;
11853                                 gpointer ptr;
11854
11855                                 CHECK_STACK_OVF (1);
11856                                 CHECK_OPSIZE (6);
11857                                 token = read32 (ip + 2);
11858
11859                                 ptr = mono_method_get_wrapper_data (method, token);
11860                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11861                                 g_assert (callinfo);
11862                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11863                                 *sp++ = ins;
11864                                 ip += 6;
11865                                 inline_costs += 10 * num_calls++;
11866                                 break;
11867                         }
11868                         case CEE_MONO_ICALL_ADDR: {
11869                                 MonoMethod *cmethod;
11870                                 gpointer ptr;
11871
11872                                 CHECK_STACK_OVF (1);
11873                                 CHECK_OPSIZE (6);
11874                                 token = read32 (ip + 2);
11875
11876                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
11877
11878                                 if (cfg->compile_aot) {
11879                                         if (cfg->direct_pinvoke && ip + 6 < end && (ip [6] == CEE_POP)) {
11880                                                 /*
11881                                                  * This is generated by emit_native_wrapper () to resolve the pinvoke address
11882                                                  * before the call, its not needed when using direct pinvoke.
11883                                                  * This is not an optimization, but its used to avoid looking up pinvokes
11884                                                  * on platforms which don't support dlopen ().
11885                                                  */
11886                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11887                                         } else {
11888                                                 EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11889                                         }
11890                                 } else {
11891                                         ptr = mono_lookup_internal_call (cmethod);
11892                                         g_assert (ptr);
11893                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11894                                 }
11895                                 *sp++ = ins;
11896                                 ip += 6;
11897                                 break;
11898                         }
11899                         case CEE_MONO_VTADDR: {
11900                                 MonoInst *src_var, *src;
11901
11902                                 CHECK_STACK (1);
11903                                 --sp;
11904
11905                                 // FIXME:
11906                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11907                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11908                                 *sp++ = src;
11909                                 ip += 2;
11910                                 break;
11911                         }
11912                         case CEE_MONO_NEWOBJ: {
11913                                 MonoInst *iargs [2];
11914
11915                                 CHECK_STACK_OVF (1);
11916                                 CHECK_OPSIZE (6);
11917                                 token = read32 (ip + 2);
11918                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11919                                 mono_class_init (klass);
11920                                 NEW_DOMAINCONST (cfg, iargs [0]);
11921                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11922                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11923                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11924                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
11925                                 ip += 6;
11926                                 inline_costs += 10 * num_calls++;
11927                                 break;
11928                         }
11929                         case CEE_MONO_OBJADDR:
11930                                 CHECK_STACK (1);
11931                                 --sp;
11932                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11933                                 ins->dreg = alloc_ireg_mp (cfg);
11934                                 ins->sreg1 = sp [0]->dreg;
11935                                 ins->type = STACK_MP;
11936                                 MONO_ADD_INS (cfg->cbb, ins);
11937                                 *sp++ = ins;
11938                                 ip += 2;
11939                                 break;
11940                         case CEE_MONO_LDNATIVEOBJ:
11941                                 /*
11942                                  * Similar to LDOBJ, but instead load the unmanaged 
11943                                  * representation of the vtype to the stack.
11944                                  */
11945                                 CHECK_STACK (1);
11946                                 CHECK_OPSIZE (6);
11947                                 --sp;
11948                                 token = read32 (ip + 2);
11949                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11950                                 g_assert (klass->valuetype);
11951                                 mono_class_init (klass);
11952
11953                                 {
11954                                         MonoInst *src, *dest, *temp;
11955
11956                                         src = sp [0];
11957                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11958                                         temp->backend.is_pinvoke = 1;
11959                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11960                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11961
11962                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11963                                         dest->type = STACK_VTYPE;
11964                                         dest->klass = klass;
11965
11966                                         *sp ++ = dest;
11967                                         ip += 6;
11968                                 }
11969                                 break;
11970                         case CEE_MONO_RETOBJ: {
11971                                 /*
11972                                  * Same as RET, but return the native representation of a vtype
11973                                  * to the caller.
11974                                  */
11975                                 g_assert (cfg->ret);
11976                                 g_assert (mono_method_signature (method)->pinvoke); 
11977                                 CHECK_STACK (1);
11978                                 --sp;
11979                                 
11980                                 CHECK_OPSIZE (6);
11981                                 token = read32 (ip + 2);    
11982                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11983
11984                                 if (!cfg->vret_addr) {
11985                                         g_assert (cfg->ret_var_is_local);
11986
11987                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11988                                 } else {
11989                                         EMIT_NEW_RETLOADA (cfg, ins);
11990                                 }
11991                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11992                                 
11993                                 if (sp != stack_start)
11994                                         UNVERIFIED;
11995                                 
11996                                 MONO_INST_NEW (cfg, ins, OP_BR);
11997                                 ins->inst_target_bb = end_bblock;
11998                                 MONO_ADD_INS (cfg->cbb, ins);
11999                                 link_bblock (cfg, cfg->cbb, end_bblock);
12000                                 start_new_bblock = 1;
12001                                 ip += 6;
12002                                 break;
12003                         }
12004                         case CEE_MONO_SAVE_LMF:
12005                         case CEE_MONO_RESTORE_LMF:
12006                                 ip += 2;
12007                                 break;
12008                         case CEE_MONO_CLASSCONST:
12009                                 CHECK_STACK_OVF (1);
12010                                 CHECK_OPSIZE (6);
12011                                 token = read32 (ip + 2);
12012                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12013                                 *sp++ = ins;
12014                                 ip += 6;
12015                                 inline_costs += 10 * num_calls++;
12016                                 break;
12017                         case CEE_MONO_NOT_TAKEN:
12018                                 cfg->cbb->out_of_line = TRUE;
12019                                 ip += 2;
12020                                 break;
12021                         case CEE_MONO_TLS: {
12022                                 MonoTlsKey key;
12023
12024                                 CHECK_STACK_OVF (1);
12025                                 CHECK_OPSIZE (6);
12026                                 key = (MonoTlsKey)read32 (ip + 2);
12027                                 g_assert (key < TLS_KEY_NUM);
12028
12029                                 ins = mono_create_tls_get (cfg, key);
12030                                 g_assert (ins);
12031                                 ins->type = STACK_PTR;
12032                                 *sp++ = ins;
12033                                 ip += 6;
12034                                 break;
12035                         }
12036                         case CEE_MONO_DYN_CALL: {
12037                                 MonoCallInst *call;
12038
12039                                 /* It would be easier to call a trampoline, but that would put an
12040                                  * extra frame on the stack, confusing exception handling. So
12041                                  * implement it inline using an opcode for now.
12042                                  */
12043
12044                                 if (!cfg->dyn_call_var) {
12045                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12046                                         /* prevent it from being register allocated */
12047                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12048                                 }
12049
12050                                 /* Has to use a call inst since it local regalloc expects it */
12051                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12052                                 ins = (MonoInst*)call;
12053                                 sp -= 2;
12054                                 ins->sreg1 = sp [0]->dreg;
12055                                 ins->sreg2 = sp [1]->dreg;
12056                                 MONO_ADD_INS (cfg->cbb, ins);
12057
12058                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12059
12060                                 ip += 2;
12061                                 inline_costs += 10 * num_calls++;
12062
12063                                 break;
12064                         }
12065                         case CEE_MONO_MEMORY_BARRIER: {
12066                                 CHECK_OPSIZE (6);
12067                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12068                                 ip += 6;
12069                                 break;
12070                         }
12071                         case CEE_MONO_ATOMIC_STORE_I4: {
12072                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
12073
12074                                 CHECK_OPSIZE (6);
12075                                 CHECK_STACK (2);
12076                                 sp -= 2;
12077
12078                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
12079                                 ins->dreg = sp [0]->dreg;
12080                                 ins->sreg1 = sp [1]->dreg;
12081                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
12082                                 MONO_ADD_INS (cfg->cbb, ins);
12083
12084                                 ip += 6;
12085                                 break;
12086                         }
12087                         case CEE_MONO_JIT_ATTACH: {
12088                                 MonoInst *args [16], *domain_ins;
12089                                 MonoInst *ad_ins, *jit_tls_ins;
12090                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12091
12092                                 g_assert (!mono_threads_is_coop_enabled ());
12093
12094                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12095
12096                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12097                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12098
12099                                 ad_ins = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
12100                                 jit_tls_ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
12101
12102                                 if (ad_ins && jit_tls_ins) {
12103                                         NEW_BBLOCK (cfg, next_bb);
12104                                         NEW_BBLOCK (cfg, call_bb);
12105
12106                                         if (cfg->compile_aot) {
12107                                                 /* AOT code is only used in the root domain */
12108                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12109                                         } else {
12110                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12111                                         }
12112                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12113                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12114
12115                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12116                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12117
12118                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12119                                         MONO_START_BB (cfg, call_bb);
12120                                 }
12121
12122                                 /* AOT code is only used in the root domain */
12123                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12124                                 if (cfg->compile_aot) {
12125                                         MonoInst *addr;
12126
12127                                         /*
12128                                          * This is called on unattached threads, so it cannot go through the trampoline
12129                                          * infrastructure. Use an indirect call through a got slot initialized at load time
12130                                          * instead.
12131                                          */
12132                                         EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_JIT_THREAD_ATTACH, NULL);
12133                                         ins = mono_emit_calli (cfg, helper_sig_jit_thread_attach, args, addr, NULL, NULL);
12134                                 } else {
12135                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12136                                 }
12137                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12138
12139                                 if (next_bb)
12140                                         MONO_START_BB (cfg, next_bb);
12141
12142                                 ip += 2;
12143                                 break;
12144                         }
12145                         case CEE_MONO_JIT_DETACH: {
12146                                 MonoInst *args [16];
12147
12148                                 /* Restore the original domain */
12149                                 dreg = alloc_ireg (cfg);
12150                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12151                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12152                                 ip += 2;
12153                                 break;
12154                         }
12155                         case CEE_MONO_CALLI_EXTRA_ARG: {
12156                                 MonoInst *addr;
12157                                 MonoMethodSignature *fsig;
12158                                 MonoInst *arg;
12159
12160                                 /*
12161                                  * This is the same as CEE_CALLI, but passes an additional argument
12162                                  * to the called method in llvmonly mode.
12163                                  * This is only used by delegate invoke wrappers to call the
12164                                  * actual delegate method.
12165                                  */
12166                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12167
12168                                 CHECK_OPSIZE (6);
12169                                 token = read32 (ip + 2);
12170
12171                                 ins = NULL;
12172
12173                                 cmethod = NULL;
12174                                 CHECK_STACK (1);
12175                                 --sp;
12176                                 addr = *sp;
12177                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12178                                 CHECK_CFG_ERROR;
12179
12180                                 if (cfg->llvm_only)
12181                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12182
12183                                 n = fsig->param_count + fsig->hasthis + 1;
12184
12185                                 CHECK_STACK (n);
12186
12187                                 sp -= n;
12188                                 arg = sp [n - 1];
12189
12190                                 if (cfg->llvm_only) {
12191                                         /*
12192                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12193                                          * cconv. This is set by mono_init_delegate ().
12194                                          */
12195                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12196                                                 MonoInst *callee = addr;
12197                                                 MonoInst *call, *localloc_ins;
12198                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12199                                                 int low_bit_reg = alloc_preg (cfg);
12200
12201                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12202                                                 NEW_BBLOCK (cfg, end_bb);
12203
12204                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12205                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12206                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12207
12208                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12209                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12210                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12211                                                 /*
12212                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12213                                                  */
12214                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12215                                                 ins->dreg = alloc_preg (cfg);
12216                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12217                                                 MONO_ADD_INS (cfg->cbb, ins);
12218                                                 localloc_ins = ins;
12219                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12220                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12221                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12222
12223                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12224                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12225
12226                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12227                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12228                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12229                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12230                                                 ins->dreg = call->dreg;
12231
12232                                                 MONO_START_BB (cfg, end_bb);
12233                                         } else {
12234                                                 /* Caller uses a normal calling conv */
12235
12236                                                 MonoInst *callee = addr;
12237                                                 MonoInst *call, *localloc_ins;
12238                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12239                                                 int low_bit_reg = alloc_preg (cfg);
12240
12241                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12242                                                 NEW_BBLOCK (cfg, end_bb);
12243
12244                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12245                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12246                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12247
12248                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12249                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12250                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12251                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12252                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12253                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12254                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12255                                                 MONO_ADD_INS (cfg->cbb, addr);
12256                                                 /*
12257                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12258                                                  */
12259                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12260                                                 ins->dreg = alloc_preg (cfg);
12261                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12262                                                 MONO_ADD_INS (cfg->cbb, ins);
12263                                                 localloc_ins = ins;
12264                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12265                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12266                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12267
12268                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12269                                                 ins->dreg = call->dreg;
12270                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12271
12272                                                 MONO_START_BB (cfg, end_bb);
12273                                         }
12274                                 } else {
12275                                         /* Same as CEE_CALLI */
12276                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12277                                                 /*
12278                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12279                                                  */
12280                                                 MonoInst *callee = addr;
12281
12282                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12283                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12284                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12285                                         } else {
12286                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12287                                         }
12288                                 }
12289
12290                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12291                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12292
12293                                 CHECK_CFG_EXCEPTION;
12294
12295                                 ip += 6;
12296                                 ins_flag = 0;
12297                                 constrained_class = NULL;
12298                                 break;
12299                         }
12300                         case CEE_MONO_LDDOMAIN:
12301                                 CHECK_STACK_OVF (1);
12302                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
12303                                 ip += 2;
12304                                 *sp++ = ins;
12305                                 break;
12306                         case CEE_MONO_GET_LAST_ERROR:
12307                                 CHECK_OPSIZE (2);
12308                                 CHECK_STACK_OVF (1);
12309
12310                                 MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
12311                                 ins->dreg = alloc_dreg (cfg, STACK_I4);
12312                                 ins->type = STACK_I4;
12313                                 MONO_ADD_INS (cfg->cbb, ins);
12314
12315                                 ip += 2;
12316                                 *sp++ = ins;
12317                                 break;
12318                         default:
12319                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12320                                 break;
12321                         }
12322                         break;
12323                 }
12324
12325                 case CEE_PREFIX1: {
12326                         CHECK_OPSIZE (2);
12327                         switch (ip [1]) {
12328                         case CEE_ARGLIST: {
12329                                 /* somewhat similar to LDTOKEN */
12330                                 MonoInst *addr, *vtvar;
12331                                 CHECK_STACK_OVF (1);
12332                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12333
12334                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12335                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12336
12337                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12338                                 ins->type = STACK_VTYPE;
12339                                 ins->klass = mono_defaults.argumenthandle_class;
12340                                 *sp++ = ins;
12341                                 ip += 2;
12342                                 break;
12343                         }
12344                         case CEE_CEQ:
12345                         case CEE_CGT:
12346                         case CEE_CGT_UN:
12347                         case CEE_CLT:
12348                         case CEE_CLT_UN: {
12349                                 MonoInst *cmp, *arg1, *arg2;
12350
12351                                 CHECK_STACK (2);
12352                                 sp -= 2;
12353                                 arg1 = sp [0];
12354                                 arg2 = sp [1];
12355
12356                                 /*
12357                                  * The following transforms:
12358                                  *    CEE_CEQ    into OP_CEQ
12359                                  *    CEE_CGT    into OP_CGT
12360                                  *    CEE_CGT_UN into OP_CGT_UN
12361                                  *    CEE_CLT    into OP_CLT
12362                                  *    CEE_CLT_UN into OP_CLT_UN
12363                                  */
12364                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12365
12366                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12367                                 cmp->sreg1 = arg1->dreg;
12368                                 cmp->sreg2 = arg2->dreg;
12369                                 type_from_op (cfg, cmp, arg1, arg2);
12370                                 CHECK_TYPE (cmp);
12371                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12372                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12373                                         cmp->opcode = OP_LCOMPARE;
12374                                 else if (arg1->type == STACK_R4)
12375                                         cmp->opcode = OP_RCOMPARE;
12376                                 else if (arg1->type == STACK_R8)
12377                                         cmp->opcode = OP_FCOMPARE;
12378                                 else
12379                                         cmp->opcode = OP_ICOMPARE;
12380                                 MONO_ADD_INS (cfg->cbb, cmp);
12381                                 ins->type = STACK_I4;
12382                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
12383                                 type_from_op (cfg, ins, arg1, arg2);
12384
12385                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12386                                         /*
12387                                          * The backends expect the fceq opcodes to do the
12388                                          * comparison too.
12389                                          */
12390                                         ins->sreg1 = cmp->sreg1;
12391                                         ins->sreg2 = cmp->sreg2;
12392                                         NULLIFY_INS (cmp);
12393                                 }
12394                                 MONO_ADD_INS (cfg->cbb, ins);
12395                                 *sp++ = ins;
12396                                 ip += 2;
12397                                 break;
12398                         }
12399                         case CEE_LDFTN: {
12400                                 MonoInst *argconst;
12401                                 MonoMethod *cil_method;
12402
12403                                 CHECK_STACK_OVF (1);
12404                                 CHECK_OPSIZE (6);
12405                                 n = read32 (ip + 2);
12406                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12407                                 CHECK_CFG_ERROR;
12408
12409                                 mono_class_init (cmethod->klass);
12410
12411                                 mono_save_token_info (cfg, image, n, cmethod);
12412
12413                                 context_used = mini_method_check_context_used (cfg, cmethod);
12414
12415                                 cil_method = cmethod;
12416                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12417                                         emit_method_access_failure (cfg, method, cil_method);
12418
12419                                 if (mono_security_core_clr_enabled ())
12420                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12421
12422                                 /* 
12423                                  * Optimize the common case of ldftn+delegate creation
12424                                  */
12425                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12426                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12427                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12428                                                 MonoInst *target_ins, *handle_ins;
12429                                                 MonoMethod *invoke;
12430                                                 int invoke_context_used;
12431
12432                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12433                                                 if (!invoke || !mono_method_signature (invoke))
12434                                                         LOAD_ERROR;
12435
12436                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12437
12438                                                 target_ins = sp [-1];
12439
12440                                                 if (mono_security_core_clr_enabled ())
12441                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12442
12443                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12444                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12445                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12446                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12447                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12448                                                         }
12449                                                 }
12450
12451                                                 /* FIXME: SGEN support */
12452                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12453                                                         ip += 6;
12454                                                         if (cfg->verbose_level > 3)
12455                                                                 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));
12456                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12457                                                                 sp --;
12458                                                                 *sp = handle_ins;
12459                                                                 CHECK_CFG_EXCEPTION;
12460                                                                 ip += 5;
12461                                                                 sp ++;
12462                                                                 break;
12463                                                         }
12464                                                         ip -= 6;
12465                                                 }
12466                                         }
12467                                 }
12468
12469                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12470                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12471                                 *sp++ = ins;
12472                                 
12473                                 ip += 6;
12474                                 inline_costs += 10 * num_calls++;
12475                                 break;
12476                         }
12477                         case CEE_LDVIRTFTN: {
12478                                 MonoInst *args [2];
12479
12480                                 CHECK_STACK (1);
12481                                 CHECK_OPSIZE (6);
12482                                 n = read32 (ip + 2);
12483                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12484                                 CHECK_CFG_ERROR;
12485
12486                                 mono_class_init (cmethod->klass);
12487  
12488                                 context_used = mini_method_check_context_used (cfg, cmethod);
12489
12490                                 if (mono_security_core_clr_enabled ())
12491                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12492
12493                                 /*
12494                                  * Optimize the common case of ldvirtftn+delegate creation
12495                                  */
12496                                 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)) {
12497                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12498                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12499                                                 MonoInst *target_ins, *handle_ins;
12500                                                 MonoMethod *invoke;
12501                                                 int invoke_context_used;
12502                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12503
12504                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12505                                                 if (!invoke || !mono_method_signature (invoke))
12506                                                         LOAD_ERROR;
12507
12508                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12509
12510                                                 target_ins = sp [-1];
12511
12512                                                 if (mono_security_core_clr_enabled ())
12513                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12514
12515                                                 /* FIXME: SGEN support */
12516                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12517                                                         ip += 6;
12518                                                         if (cfg->verbose_level > 3)
12519                                                                 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));
12520                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12521                                                                 sp -= 2;
12522                                                                 *sp = handle_ins;
12523                                                                 CHECK_CFG_EXCEPTION;
12524                                                                 ip += 5;
12525                                                                 sp ++;
12526                                                                 break;
12527                                                         }
12528                                                         ip -= 6;
12529                                                 }
12530                                         }
12531                                 }
12532
12533                                 --sp;
12534                                 args [0] = *sp;
12535
12536                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12537                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12538
12539                                 if (context_used)
12540                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12541                                 else
12542                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12543
12544                                 ip += 6;
12545                                 inline_costs += 10 * num_calls++;
12546                                 break;
12547                         }
12548                         case CEE_LDARG:
12549                                 CHECK_STACK_OVF (1);
12550                                 CHECK_OPSIZE (4);
12551                                 n = read16 (ip + 2);
12552                                 CHECK_ARG (n);
12553                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12554                                 *sp++ = ins;
12555                                 ip += 4;
12556                                 break;
12557                         case CEE_LDARGA:
12558                                 CHECK_STACK_OVF (1);
12559                                 CHECK_OPSIZE (4);
12560                                 n = read16 (ip + 2);
12561                                 CHECK_ARG (n);
12562                                 NEW_ARGLOADA (cfg, ins, n);
12563                                 MONO_ADD_INS (cfg->cbb, ins);
12564                                 *sp++ = ins;
12565                                 ip += 4;
12566                                 break;
12567                         case CEE_STARG:
12568                                 CHECK_STACK (1);
12569                                 --sp;
12570                                 CHECK_OPSIZE (4);
12571                                 n = read16 (ip + 2);
12572                                 CHECK_ARG (n);
12573                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12574                                         UNVERIFIED;
12575                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12576                                 ip += 4;
12577                                 break;
12578                         case CEE_LDLOC:
12579                                 CHECK_STACK_OVF (1);
12580                                 CHECK_OPSIZE (4);
12581                                 n = read16 (ip + 2);
12582                                 CHECK_LOCAL (n);
12583                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12584                                 *sp++ = ins;
12585                                 ip += 4;
12586                                 break;
12587                         case CEE_LDLOCA: {
12588                                 unsigned char *tmp_ip;
12589                                 CHECK_STACK_OVF (1);
12590                                 CHECK_OPSIZE (4);
12591                                 n = read16 (ip + 2);
12592                                 CHECK_LOCAL (n);
12593
12594                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12595                                         ip = tmp_ip;
12596                                         inline_costs += 1;
12597                                         break;
12598                                 }                       
12599                                 
12600                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12601                                 *sp++ = ins;
12602                                 ip += 4;
12603                                 break;
12604                         }
12605                         case CEE_STLOC:
12606                                 CHECK_STACK (1);
12607                                 --sp;
12608                                 CHECK_OPSIZE (4);
12609                                 n = read16 (ip + 2);
12610                                 CHECK_LOCAL (n);
12611                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12612                                         UNVERIFIED;
12613                                 emit_stloc_ir (cfg, sp, header, n);
12614                                 ip += 4;
12615                                 inline_costs += 1;
12616                                 break;
12617                         case CEE_LOCALLOC: {
12618                                 CHECK_STACK (1);
12619                                 MonoBasicBlock *non_zero_bb, *end_bb;
12620                                 int alloc_ptr = alloc_preg (cfg);
12621                                 --sp;
12622                                 if (sp != stack_start) 
12623                                         UNVERIFIED;
12624                                 if (cfg->method != method) 
12625                                         /* 
12626                                          * Inlining this into a loop in a parent could lead to 
12627                                          * stack overflows which is different behavior than the
12628                                          * non-inlined case, thus disable inlining in this case.
12629                                          */
12630                                         INLINE_FAILURE("localloc");
12631
12632                                 NEW_BBLOCK (cfg, non_zero_bb);
12633                                 NEW_BBLOCK (cfg, end_bb);
12634
12635                                 /* if size != zero */
12636                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
12637                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
12638
12639                                 //size is zero, so result is NULL
12640                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
12641                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12642
12643                                 MONO_START_BB (cfg, non_zero_bb);
12644                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12645                                 ins->dreg = alloc_ptr;
12646                                 ins->sreg1 = sp [0]->dreg;
12647                                 ins->type = STACK_PTR;
12648                                 MONO_ADD_INS (cfg->cbb, ins);
12649
12650                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12651                                 if (init_locals)
12652                                         ins->flags |= MONO_INST_INIT;
12653
12654                                 MONO_START_BB (cfg, end_bb);
12655                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
12656                                 ins->type = STACK_PTR;
12657
12658                                 *sp++ = ins;
12659                                 ip += 2;
12660                                 break;
12661                         }
12662                         case CEE_ENDFILTER: {
12663                                 MonoExceptionClause *clause, *nearest;
12664                                 int cc;
12665
12666                                 CHECK_STACK (1);
12667                                 --sp;
12668                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12669                                         UNVERIFIED;
12670                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12671                                 ins->sreg1 = (*sp)->dreg;
12672                                 MONO_ADD_INS (cfg->cbb, ins);
12673                                 start_new_bblock = 1;
12674                                 ip += 2;
12675
12676                                 nearest = NULL;
12677                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12678                                         clause = &header->clauses [cc];
12679                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12680                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12681                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12682                                                 nearest = clause;
12683                                 }
12684                                 g_assert (nearest);
12685                                 if ((ip - header->code) != nearest->handler_offset)
12686                                         UNVERIFIED;
12687
12688                                 break;
12689                         }
12690                         case CEE_UNALIGNED_:
12691                                 ins_flag |= MONO_INST_UNALIGNED;
12692                                 /* FIXME: record alignment? we can assume 1 for now */
12693                                 CHECK_OPSIZE (3);
12694                                 ip += 3;
12695                                 break;
12696                         case CEE_VOLATILE_:
12697                                 ins_flag |= MONO_INST_VOLATILE;
12698                                 ip += 2;
12699                                 break;
12700                         case CEE_TAIL_:
12701                                 ins_flag   |= MONO_INST_TAILCALL;
12702                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12703                                 /* Can't inline tail calls at this time */
12704                                 inline_costs += 100000;
12705                                 ip += 2;
12706                                 break;
12707                         case CEE_INITOBJ:
12708                                 CHECK_STACK (1);
12709                                 --sp;
12710                                 CHECK_OPSIZE (6);
12711                                 token = read32 (ip + 2);
12712                                 klass = mini_get_class (method, token, generic_context);
12713                                 CHECK_TYPELOAD (klass);
12714                                 if (generic_class_is_reference_type (cfg, klass))
12715                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12716                                 else
12717                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12718                                 ip += 6;
12719                                 inline_costs += 1;
12720                                 break;
12721                         case CEE_CONSTRAINED_:
12722                                 CHECK_OPSIZE (6);
12723                                 token = read32 (ip + 2);
12724                                 constrained_class = mini_get_class (method, token, generic_context);
12725                                 CHECK_TYPELOAD (constrained_class);
12726                                 ip += 6;
12727                                 break;
12728                         case CEE_CPBLK:
12729                         case CEE_INITBLK: {
12730                                 MonoInst *iargs [3];
12731                                 CHECK_STACK (3);
12732                                 sp -= 3;
12733
12734                                 /* Skip optimized paths for volatile operations. */
12735                                 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)) {
12736                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12737                                 } 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)) {
12738                                         /* emit_memset only works when val == 0 */
12739                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12740                                 } else {
12741                                         MonoInst *call;
12742                                         iargs [0] = sp [0];
12743                                         iargs [1] = sp [1];
12744                                         iargs [2] = sp [2];
12745                                         if (ip [1] == CEE_CPBLK) {
12746                                                 /*
12747                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12748                                                  * and release barriers for cpblk. It is technically both a load and
12749                                                  * store operation, so it seems like that's the sensible thing to do.
12750                                                  *
12751                                                  * FIXME: We emit full barriers on both sides of the operation for
12752                                                  * simplicity. We should have a separate atomic memcpy method instead.
12753                                                  */
12754                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12755
12756                                                 if (ins_flag & MONO_INST_VOLATILE)
12757                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12758
12759                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12760                                                 call->flags |= ins_flag;
12761
12762                                                 if (ins_flag & MONO_INST_VOLATILE)
12763                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12764                                         } else {
12765                                                 MonoMethod *memset_method = get_memset_method ();
12766                                                 if (ins_flag & MONO_INST_VOLATILE) {
12767                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12768                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12769                                                 }
12770                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12771                                                 call->flags |= ins_flag;
12772                                         }
12773                                 }
12774                                 ip += 2;
12775                                 ins_flag = 0;
12776                                 inline_costs += 1;
12777                                 break;
12778                         }
12779                         case CEE_NO_:
12780                                 CHECK_OPSIZE (3);
12781                                 if (ip [2] & 0x1)
12782                                         ins_flag |= MONO_INST_NOTYPECHECK;
12783                                 if (ip [2] & 0x2)
12784                                         ins_flag |= MONO_INST_NORANGECHECK;
12785                                 /* we ignore the no-nullcheck for now since we
12786                                  * really do it explicitly only when doing callvirt->call
12787                                  */
12788                                 ip += 3;
12789                                 break;
12790                         case CEE_RETHROW: {
12791                                 MonoInst *load;
12792                                 int handler_offset = -1;
12793
12794                                 for (i = 0; i < header->num_clauses; ++i) {
12795                                         MonoExceptionClause *clause = &header->clauses [i];
12796                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12797                                                 handler_offset = clause->handler_offset;
12798                                                 break;
12799                                         }
12800                                 }
12801
12802                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12803
12804                                 if (handler_offset == -1)
12805                                         UNVERIFIED;
12806
12807                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12808                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12809                                 ins->sreg1 = load->dreg;
12810                                 MONO_ADD_INS (cfg->cbb, ins);
12811
12812                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12813                                 MONO_ADD_INS (cfg->cbb, ins);
12814
12815                                 sp = stack_start;
12816                                 link_bblock (cfg, cfg->cbb, end_bblock);
12817                                 start_new_bblock = 1;
12818                                 ip += 2;
12819                                 break;
12820                         }
12821                         case CEE_SIZEOF: {
12822                                 guint32 val;
12823                                 int ialign;
12824
12825                                 CHECK_STACK_OVF (1);
12826                                 CHECK_OPSIZE (6);
12827                                 token = read32 (ip + 2);
12828                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12829                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12830                                         CHECK_CFG_ERROR;
12831
12832                                         val = mono_type_size (type, &ialign);
12833                                 } else {
12834                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12835                                         CHECK_TYPELOAD (klass);
12836
12837                                         val = mono_type_size (&klass->byval_arg, &ialign);
12838
12839                                         if (mini_is_gsharedvt_klass (klass))
12840                                                 GSHAREDVT_FAILURE (*ip);
12841                                 }
12842                                 EMIT_NEW_ICONST (cfg, ins, val);
12843                                 *sp++= ins;
12844                                 ip += 6;
12845                                 break;
12846                         }
12847                         case CEE_REFANYTYPE: {
12848                                 MonoInst *src_var, *src;
12849
12850                                 GSHAREDVT_FAILURE (*ip);
12851
12852                                 CHECK_STACK (1);
12853                                 --sp;
12854
12855                                 // FIXME:
12856                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12857                                 if (!src_var)
12858                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12859                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12860                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12861                                 *sp++ = ins;
12862                                 ip += 2;
12863                                 break;
12864                         }
12865                         case CEE_READONLY_:
12866                                 readonly = TRUE;
12867                                 ip += 2;
12868                                 break;
12869
12870                         case CEE_UNUSED56:
12871                         case CEE_UNUSED57:
12872                         case CEE_UNUSED70:
12873                         case CEE_UNUSED:
12874                         case CEE_UNUSED99:
12875                                 UNVERIFIED;
12876                                 
12877                         default:
12878                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12879                                 UNVERIFIED;
12880                         }
12881                         break;
12882                 }
12883                 case CEE_UNUSED58:
12884                 case CEE_UNUSED1:
12885                         UNVERIFIED;
12886
12887                 default:
12888                         g_warning ("opcode 0x%02x not handled", *ip);
12889                         UNVERIFIED;
12890                 }
12891         }
12892         if (start_new_bblock != 1)
12893                 UNVERIFIED;
12894
12895         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
12896         if (cfg->cbb->next_bb) {
12897                 /* This could already be set because of inlining, #693905 */
12898                 MonoBasicBlock *bb = cfg->cbb;
12899
12900                 while (bb->next_bb)
12901                         bb = bb->next_bb;
12902                 bb->next_bb = end_bblock;
12903         } else {
12904                 cfg->cbb->next_bb = end_bblock;
12905         }
12906
12907         if (cfg->method == method && cfg->domainvar) {
12908                 MonoInst *store;
12909                 MonoInst *get_domain;
12910
12911                 cfg->cbb = init_localsbb;
12912
12913                 get_domain = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
12914                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12915                 MONO_ADD_INS (cfg->cbb, store);
12916         }
12917
12918 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12919         if (cfg->compile_aot)
12920                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12921                 mono_get_got_var (cfg);
12922 #endif
12923
12924         if (cfg->method == method && cfg->got_var)
12925                 mono_emit_load_got_addr (cfg);
12926
12927         if (init_localsbb) {
12928                 cfg->cbb = init_localsbb;
12929                 cfg->ip = NULL;
12930                 for (i = 0; i < header->num_locals; ++i) {
12931                         emit_init_local (cfg, i, header->locals [i], init_locals);
12932                 }
12933         }
12934
12935         if (cfg->init_ref_vars && cfg->method == method) {
12936                 /* Emit initialization for ref vars */
12937                 // FIXME: Avoid duplication initialization for IL locals.
12938                 for (i = 0; i < cfg->num_varinfo; ++i) {
12939                         MonoInst *ins = cfg->varinfo [i];
12940
12941                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12942                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12943                 }
12944         }
12945
12946         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
12947                 cfg->cbb = init_localsbb;
12948                 emit_push_lmf (cfg);
12949         }
12950
12951         cfg->cbb = init_localsbb;
12952         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12953
12954         if (seq_points) {
12955                 MonoBasicBlock *bb;
12956
12957                 /*
12958                  * Make seq points at backward branch targets interruptable.
12959                  */
12960                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12961                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12962                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12963         }
12964
12965         /* Add a sequence point for method entry/exit events */
12966         if (seq_points && cfg->gen_sdb_seq_points) {
12967                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12968                 MONO_ADD_INS (init_localsbb, ins);
12969                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12970                 MONO_ADD_INS (cfg->bb_exit, ins);
12971         }
12972
12973         /*
12974          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12975          * the code they refer to was dead (#11880).
12976          */
12977         if (sym_seq_points) {
12978                 for (i = 0; i < header->code_size; ++i) {
12979                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12980                                 MonoInst *ins;
12981
12982                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12983                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12984                         }
12985                 }
12986         }
12987
12988         cfg->ip = NULL;
12989
12990         if (cfg->method == method) {
12991                 MonoBasicBlock *bb;
12992                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12993                         if (bb == cfg->bb_init)
12994                                 bb->region = -1;
12995                         else
12996                                 bb->region = mono_find_block_region (cfg, bb->real_offset);
12997                         if (cfg->spvars)
12998                                 mono_create_spvar_for_region (cfg, bb->region);
12999                         if (cfg->verbose_level > 2)
13000                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13001                 }
13002         } else {
13003                 MonoBasicBlock *bb;
13004                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
13005                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
13006                         bb->real_offset = inline_offset;
13007                 }
13008         }
13009
13010         if (inline_costs < 0) {
13011                 char *mname;
13012
13013                 /* Method is too large */
13014                 mname = mono_method_full_name (method, TRUE);
13015                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13016                 g_free (mname);
13017         }
13018
13019         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13020                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13021
13022         goto cleanup;
13023
13024 mono_error_exit:
13025         g_assert (!mono_error_ok (&cfg->error));
13026         goto cleanup;
13027  
13028  exception_exit:
13029         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13030         goto cleanup;
13031
13032  unverified:
13033         set_exception_type_from_invalid_il (cfg, method, ip);
13034         goto cleanup;
13035
13036  cleanup:
13037         g_slist_free (class_inits);
13038         mono_basic_block_free (original_bb);
13039         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13040         if (cfg->exception_type)
13041                 return -1;
13042         else
13043                 return inline_costs;
13044 }
13045
13046 static int
13047 store_membase_reg_to_store_membase_imm (int opcode)
13048 {
13049         switch (opcode) {
13050         case OP_STORE_MEMBASE_REG:
13051                 return OP_STORE_MEMBASE_IMM;
13052         case OP_STOREI1_MEMBASE_REG:
13053                 return OP_STOREI1_MEMBASE_IMM;
13054         case OP_STOREI2_MEMBASE_REG:
13055                 return OP_STOREI2_MEMBASE_IMM;
13056         case OP_STOREI4_MEMBASE_REG:
13057                 return OP_STOREI4_MEMBASE_IMM;
13058         case OP_STOREI8_MEMBASE_REG:
13059                 return OP_STOREI8_MEMBASE_IMM;
13060         default:
13061                 g_assert_not_reached ();
13062         }
13063
13064         return -1;
13065 }               
13066
13067 int
13068 mono_op_to_op_imm (int opcode)
13069 {
13070         switch (opcode) {
13071         case OP_IADD:
13072                 return OP_IADD_IMM;
13073         case OP_ISUB:
13074                 return OP_ISUB_IMM;
13075         case OP_IDIV:
13076                 return OP_IDIV_IMM;
13077         case OP_IDIV_UN:
13078                 return OP_IDIV_UN_IMM;
13079         case OP_IREM:
13080                 return OP_IREM_IMM;
13081         case OP_IREM_UN:
13082                 return OP_IREM_UN_IMM;
13083         case OP_IMUL:
13084                 return OP_IMUL_IMM;
13085         case OP_IAND:
13086                 return OP_IAND_IMM;
13087         case OP_IOR:
13088                 return OP_IOR_IMM;
13089         case OP_IXOR:
13090                 return OP_IXOR_IMM;
13091         case OP_ISHL:
13092                 return OP_ISHL_IMM;
13093         case OP_ISHR:
13094                 return OP_ISHR_IMM;
13095         case OP_ISHR_UN:
13096                 return OP_ISHR_UN_IMM;
13097
13098         case OP_LADD:
13099                 return OP_LADD_IMM;
13100         case OP_LSUB:
13101                 return OP_LSUB_IMM;
13102         case OP_LAND:
13103                 return OP_LAND_IMM;
13104         case OP_LOR:
13105                 return OP_LOR_IMM;
13106         case OP_LXOR:
13107                 return OP_LXOR_IMM;
13108         case OP_LSHL:
13109                 return OP_LSHL_IMM;
13110         case OP_LSHR:
13111                 return OP_LSHR_IMM;
13112         case OP_LSHR_UN:
13113                 return OP_LSHR_UN_IMM;
13114 #if SIZEOF_REGISTER == 8
13115         case OP_LREM:
13116                 return OP_LREM_IMM;
13117 #endif
13118
13119         case OP_COMPARE:
13120                 return OP_COMPARE_IMM;
13121         case OP_ICOMPARE:
13122                 return OP_ICOMPARE_IMM;
13123         case OP_LCOMPARE:
13124                 return OP_LCOMPARE_IMM;
13125
13126         case OP_STORE_MEMBASE_REG:
13127                 return OP_STORE_MEMBASE_IMM;
13128         case OP_STOREI1_MEMBASE_REG:
13129                 return OP_STOREI1_MEMBASE_IMM;
13130         case OP_STOREI2_MEMBASE_REG:
13131                 return OP_STOREI2_MEMBASE_IMM;
13132         case OP_STOREI4_MEMBASE_REG:
13133                 return OP_STOREI4_MEMBASE_IMM;
13134
13135 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13136         case OP_X86_PUSH:
13137                 return OP_X86_PUSH_IMM;
13138         case OP_X86_COMPARE_MEMBASE_REG:
13139                 return OP_X86_COMPARE_MEMBASE_IMM;
13140 #endif
13141 #if defined(TARGET_AMD64)
13142         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13143                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13144 #endif
13145         case OP_VOIDCALL_REG:
13146                 return OP_VOIDCALL;
13147         case OP_CALL_REG:
13148                 return OP_CALL;
13149         case OP_LCALL_REG:
13150                 return OP_LCALL;
13151         case OP_FCALL_REG:
13152                 return OP_FCALL;
13153         case OP_LOCALLOC:
13154                 return OP_LOCALLOC_IMM;
13155         }
13156
13157         return -1;
13158 }
13159
13160 static int
13161 ldind_to_load_membase (int opcode)
13162 {
13163         switch (opcode) {
13164         case CEE_LDIND_I1:
13165                 return OP_LOADI1_MEMBASE;
13166         case CEE_LDIND_U1:
13167                 return OP_LOADU1_MEMBASE;
13168         case CEE_LDIND_I2:
13169                 return OP_LOADI2_MEMBASE;
13170         case CEE_LDIND_U2:
13171                 return OP_LOADU2_MEMBASE;
13172         case CEE_LDIND_I4:
13173                 return OP_LOADI4_MEMBASE;
13174         case CEE_LDIND_U4:
13175                 return OP_LOADU4_MEMBASE;
13176         case CEE_LDIND_I:
13177                 return OP_LOAD_MEMBASE;
13178         case CEE_LDIND_REF:
13179                 return OP_LOAD_MEMBASE;
13180         case CEE_LDIND_I8:
13181                 return OP_LOADI8_MEMBASE;
13182         case CEE_LDIND_R4:
13183                 return OP_LOADR4_MEMBASE;
13184         case CEE_LDIND_R8:
13185                 return OP_LOADR8_MEMBASE;
13186         default:
13187                 g_assert_not_reached ();
13188         }
13189
13190         return -1;
13191 }
13192
13193 static int
13194 stind_to_store_membase (int opcode)
13195 {
13196         switch (opcode) {
13197         case CEE_STIND_I1:
13198                 return OP_STOREI1_MEMBASE_REG;
13199         case CEE_STIND_I2:
13200                 return OP_STOREI2_MEMBASE_REG;
13201         case CEE_STIND_I4:
13202                 return OP_STOREI4_MEMBASE_REG;
13203         case CEE_STIND_I:
13204         case CEE_STIND_REF:
13205                 return OP_STORE_MEMBASE_REG;
13206         case CEE_STIND_I8:
13207                 return OP_STOREI8_MEMBASE_REG;
13208         case CEE_STIND_R4:
13209                 return OP_STORER4_MEMBASE_REG;
13210         case CEE_STIND_R8:
13211                 return OP_STORER8_MEMBASE_REG;
13212         default:
13213                 g_assert_not_reached ();
13214         }
13215
13216         return -1;
13217 }
13218
13219 int
13220 mono_load_membase_to_load_mem (int opcode)
13221 {
13222         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13223 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13224         switch (opcode) {
13225         case OP_LOAD_MEMBASE:
13226                 return OP_LOAD_MEM;
13227         case OP_LOADU1_MEMBASE:
13228                 return OP_LOADU1_MEM;
13229         case OP_LOADU2_MEMBASE:
13230                 return OP_LOADU2_MEM;
13231         case OP_LOADI4_MEMBASE:
13232                 return OP_LOADI4_MEM;
13233         case OP_LOADU4_MEMBASE:
13234                 return OP_LOADU4_MEM;
13235 #if SIZEOF_REGISTER == 8
13236         case OP_LOADI8_MEMBASE:
13237                 return OP_LOADI8_MEM;
13238 #endif
13239         }
13240 #endif
13241
13242         return -1;
13243 }
13244
13245 static inline int
13246 op_to_op_dest_membase (int store_opcode, int opcode)
13247 {
13248 #if defined(TARGET_X86)
13249         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13250                 return -1;
13251
13252         switch (opcode) {
13253         case OP_IADD:
13254                 return OP_X86_ADD_MEMBASE_REG;
13255         case OP_ISUB:
13256                 return OP_X86_SUB_MEMBASE_REG;
13257         case OP_IAND:
13258                 return OP_X86_AND_MEMBASE_REG;
13259         case OP_IOR:
13260                 return OP_X86_OR_MEMBASE_REG;
13261         case OP_IXOR:
13262                 return OP_X86_XOR_MEMBASE_REG;
13263         case OP_ADD_IMM:
13264         case OP_IADD_IMM:
13265                 return OP_X86_ADD_MEMBASE_IMM;
13266         case OP_SUB_IMM:
13267         case OP_ISUB_IMM:
13268                 return OP_X86_SUB_MEMBASE_IMM;
13269         case OP_AND_IMM:
13270         case OP_IAND_IMM:
13271                 return OP_X86_AND_MEMBASE_IMM;
13272         case OP_OR_IMM:
13273         case OP_IOR_IMM:
13274                 return OP_X86_OR_MEMBASE_IMM;
13275         case OP_XOR_IMM:
13276         case OP_IXOR_IMM:
13277                 return OP_X86_XOR_MEMBASE_IMM;
13278         case OP_MOVE:
13279                 return OP_NOP;
13280         }
13281 #endif
13282
13283 #if defined(TARGET_AMD64)
13284         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13285                 return -1;
13286
13287         switch (opcode) {
13288         case OP_IADD:
13289                 return OP_X86_ADD_MEMBASE_REG;
13290         case OP_ISUB:
13291                 return OP_X86_SUB_MEMBASE_REG;
13292         case OP_IAND:
13293                 return OP_X86_AND_MEMBASE_REG;
13294         case OP_IOR:
13295                 return OP_X86_OR_MEMBASE_REG;
13296         case OP_IXOR:
13297                 return OP_X86_XOR_MEMBASE_REG;
13298         case OP_IADD_IMM:
13299                 return OP_X86_ADD_MEMBASE_IMM;
13300         case OP_ISUB_IMM:
13301                 return OP_X86_SUB_MEMBASE_IMM;
13302         case OP_IAND_IMM:
13303                 return OP_X86_AND_MEMBASE_IMM;
13304         case OP_IOR_IMM:
13305                 return OP_X86_OR_MEMBASE_IMM;
13306         case OP_IXOR_IMM:
13307                 return OP_X86_XOR_MEMBASE_IMM;
13308         case OP_LADD:
13309                 return OP_AMD64_ADD_MEMBASE_REG;
13310         case OP_LSUB:
13311                 return OP_AMD64_SUB_MEMBASE_REG;
13312         case OP_LAND:
13313                 return OP_AMD64_AND_MEMBASE_REG;
13314         case OP_LOR:
13315                 return OP_AMD64_OR_MEMBASE_REG;
13316         case OP_LXOR:
13317                 return OP_AMD64_XOR_MEMBASE_REG;
13318         case OP_ADD_IMM:
13319         case OP_LADD_IMM:
13320                 return OP_AMD64_ADD_MEMBASE_IMM;
13321         case OP_SUB_IMM:
13322         case OP_LSUB_IMM:
13323                 return OP_AMD64_SUB_MEMBASE_IMM;
13324         case OP_AND_IMM:
13325         case OP_LAND_IMM:
13326                 return OP_AMD64_AND_MEMBASE_IMM;
13327         case OP_OR_IMM:
13328         case OP_LOR_IMM:
13329                 return OP_AMD64_OR_MEMBASE_IMM;
13330         case OP_XOR_IMM:
13331         case OP_LXOR_IMM:
13332                 return OP_AMD64_XOR_MEMBASE_IMM;
13333         case OP_MOVE:
13334                 return OP_NOP;
13335         }
13336 #endif
13337
13338         return -1;
13339 }
13340
13341 static inline int
13342 op_to_op_store_membase (int store_opcode, int opcode)
13343 {
13344 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13345         switch (opcode) {
13346         case OP_ICEQ:
13347                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13348                         return OP_X86_SETEQ_MEMBASE;
13349         case OP_CNE:
13350                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13351                         return OP_X86_SETNE_MEMBASE;
13352         }
13353 #endif
13354
13355         return -1;
13356 }
13357
13358 static inline int
13359 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13360 {
13361 #ifdef TARGET_X86
13362         /* FIXME: This has sign extension issues */
13363         /*
13364         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13365                 return OP_X86_COMPARE_MEMBASE8_IMM;
13366         */
13367
13368         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13369                 return -1;
13370
13371         switch (opcode) {
13372         case OP_X86_PUSH:
13373                 return OP_X86_PUSH_MEMBASE;
13374         case OP_COMPARE_IMM:
13375         case OP_ICOMPARE_IMM:
13376                 return OP_X86_COMPARE_MEMBASE_IMM;
13377         case OP_COMPARE:
13378         case OP_ICOMPARE:
13379                 return OP_X86_COMPARE_MEMBASE_REG;
13380         }
13381 #endif
13382
13383 #ifdef TARGET_AMD64
13384         /* FIXME: This has sign extension issues */
13385         /*
13386         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13387                 return OP_X86_COMPARE_MEMBASE8_IMM;
13388         */
13389
13390         switch (opcode) {
13391         case OP_X86_PUSH:
13392                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13393                         return OP_X86_PUSH_MEMBASE;
13394                 break;
13395                 /* FIXME: This only works for 32 bit immediates
13396         case OP_COMPARE_IMM:
13397         case OP_LCOMPARE_IMM:
13398                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13399                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13400                 */
13401         case OP_ICOMPARE_IMM:
13402                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13403                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13404                 break;
13405         case OP_COMPARE:
13406         case OP_LCOMPARE:
13407                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
13408                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13409                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13410                         return OP_AMD64_COMPARE_MEMBASE_REG;
13411                 break;
13412         case OP_ICOMPARE:
13413                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13414                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13415                 break;
13416         }
13417 #endif
13418
13419         return -1;
13420 }
13421
13422 static inline int
13423 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
13424 {
13425 #ifdef TARGET_X86
13426         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13427                 return -1;
13428         
13429         switch (opcode) {
13430         case OP_COMPARE:
13431         case OP_ICOMPARE:
13432                 return OP_X86_COMPARE_REG_MEMBASE;
13433         case OP_IADD:
13434                 return OP_X86_ADD_REG_MEMBASE;
13435         case OP_ISUB:
13436                 return OP_X86_SUB_REG_MEMBASE;
13437         case OP_IAND:
13438                 return OP_X86_AND_REG_MEMBASE;
13439         case OP_IOR:
13440                 return OP_X86_OR_REG_MEMBASE;
13441         case OP_IXOR:
13442                 return OP_X86_XOR_REG_MEMBASE;
13443         }
13444 #endif
13445
13446 #ifdef TARGET_AMD64
13447         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
13448                 switch (opcode) {
13449                 case OP_ICOMPARE:
13450                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13451                 case OP_IADD:
13452                         return OP_X86_ADD_REG_MEMBASE;
13453                 case OP_ISUB:
13454                         return OP_X86_SUB_REG_MEMBASE;
13455                 case OP_IAND:
13456                         return OP_X86_AND_REG_MEMBASE;
13457                 case OP_IOR:
13458                         return OP_X86_OR_REG_MEMBASE;
13459                 case OP_IXOR:
13460                         return OP_X86_XOR_REG_MEMBASE;
13461                 }
13462         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
13463                 switch (opcode) {
13464                 case OP_COMPARE:
13465                 case OP_LCOMPARE:
13466                         return OP_AMD64_COMPARE_REG_MEMBASE;
13467                 case OP_LADD:
13468                         return OP_AMD64_ADD_REG_MEMBASE;
13469                 case OP_LSUB:
13470                         return OP_AMD64_SUB_REG_MEMBASE;
13471                 case OP_LAND:
13472                         return OP_AMD64_AND_REG_MEMBASE;
13473                 case OP_LOR:
13474                         return OP_AMD64_OR_REG_MEMBASE;
13475                 case OP_LXOR:
13476                         return OP_AMD64_XOR_REG_MEMBASE;
13477                 }
13478         }
13479 #endif
13480
13481         return -1;
13482 }
13483
13484 int
13485 mono_op_to_op_imm_noemul (int opcode)
13486 {
13487         switch (opcode) {
13488 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13489         case OP_LSHR:
13490         case OP_LSHL:
13491         case OP_LSHR_UN:
13492                 return -1;
13493 #endif
13494 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13495         case OP_IDIV:
13496         case OP_IDIV_UN:
13497         case OP_IREM:
13498         case OP_IREM_UN:
13499                 return -1;
13500 #endif
13501 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13502         case OP_IMUL:
13503                 return -1;
13504 #endif
13505         default:
13506                 return mono_op_to_op_imm (opcode);
13507         }
13508 }
13509
13510 /**
13511  * mono_handle_global_vregs:
13512  *
13513  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13514  * for them.
13515  */
13516 void
13517 mono_handle_global_vregs (MonoCompile *cfg)
13518 {
13519         gint32 *vreg_to_bb;
13520         MonoBasicBlock *bb;
13521         int i, pos;
13522
13523         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13524
13525 #ifdef MONO_ARCH_SIMD_INTRINSICS
13526         if (cfg->uses_simd_intrinsics)
13527                 mono_simd_simplify_indirection (cfg);
13528 #endif
13529
13530         /* Find local vregs used in more than one bb */
13531         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13532                 MonoInst *ins = bb->code;       
13533                 int block_num = bb->block_num;
13534
13535                 if (cfg->verbose_level > 2)
13536                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13537
13538                 cfg->cbb = bb;
13539                 for (; ins; ins = ins->next) {
13540                         const char *spec = INS_INFO (ins->opcode);
13541                         int regtype = 0, regindex;
13542                         gint32 prev_bb;
13543
13544                         if (G_UNLIKELY (cfg->verbose_level > 2))
13545                                 mono_print_ins (ins);
13546
13547                         g_assert (ins->opcode >= MONO_CEE_LAST);
13548
13549                         for (regindex = 0; regindex < 4; regindex ++) {
13550                                 int vreg = 0;
13551
13552                                 if (regindex == 0) {
13553                                         regtype = spec [MONO_INST_DEST];
13554                                         if (regtype == ' ')
13555                                                 continue;
13556                                         vreg = ins->dreg;
13557                                 } else if (regindex == 1) {
13558                                         regtype = spec [MONO_INST_SRC1];
13559                                         if (regtype == ' ')
13560                                                 continue;
13561                                         vreg = ins->sreg1;
13562                                 } else if (regindex == 2) {
13563                                         regtype = spec [MONO_INST_SRC2];
13564                                         if (regtype == ' ')
13565                                                 continue;
13566                                         vreg = ins->sreg2;
13567                                 } else if (regindex == 3) {
13568                                         regtype = spec [MONO_INST_SRC3];
13569                                         if (regtype == ' ')
13570                                                 continue;
13571                                         vreg = ins->sreg3;
13572                                 }
13573
13574 #if SIZEOF_REGISTER == 4
13575                                 /* In the LLVM case, the long opcodes are not decomposed */
13576                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13577                                         /*
13578                                          * Since some instructions reference the original long vreg,
13579                                          * and some reference the two component vregs, it is quite hard
13580                                          * to determine when it needs to be global. So be conservative.
13581                                          */
13582                                         if (!get_vreg_to_inst (cfg, vreg)) {
13583                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13584
13585                                                 if (cfg->verbose_level > 2)
13586                                                         printf ("LONG VREG R%d made global.\n", vreg);
13587                                         }
13588
13589                                         /*
13590                                          * Make the component vregs volatile since the optimizations can
13591                                          * get confused otherwise.
13592                                          */
13593                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
13594                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
13595                                 }
13596 #endif
13597
13598                                 g_assert (vreg != -1);
13599
13600                                 prev_bb = vreg_to_bb [vreg];
13601                                 if (prev_bb == 0) {
13602                                         /* 0 is a valid block num */
13603                                         vreg_to_bb [vreg] = block_num + 1;
13604                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13605                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13606                                                 continue;
13607
13608                                         if (!get_vreg_to_inst (cfg, vreg)) {
13609                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13610                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13611
13612                                                 switch (regtype) {
13613                                                 case 'i':
13614                                                         if (vreg_is_ref (cfg, vreg))
13615                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13616                                                         else
13617                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13618                                                         break;
13619                                                 case 'l':
13620                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13621                                                         break;
13622                                                 case 'f':
13623                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13624                                                         break;
13625                                                 case 'v':
13626                                                 case 'x':
13627                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13628                                                         break;
13629                                                 default:
13630                                                         g_assert_not_reached ();
13631                                                 }
13632                                         }
13633
13634                                         /* Flag as having been used in more than one bb */
13635                                         vreg_to_bb [vreg] = -1;
13636                                 }
13637                         }
13638                 }
13639         }
13640
13641         /* If a variable is used in only one bblock, convert it into a local vreg */
13642         for (i = 0; i < cfg->num_varinfo; i++) {
13643                 MonoInst *var = cfg->varinfo [i];
13644                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13645
13646                 switch (var->type) {
13647                 case STACK_I4:
13648                 case STACK_OBJ:
13649                 case STACK_PTR:
13650                 case STACK_MP:
13651                 case STACK_VTYPE:
13652 #if SIZEOF_REGISTER == 8
13653                 case STACK_I8:
13654 #endif
13655 #if !defined(TARGET_X86)
13656                 /* Enabling this screws up the fp stack on x86 */
13657                 case STACK_R8:
13658 #endif
13659                         if (mono_arch_is_soft_float ())
13660                                 break;
13661
13662                         /*
13663                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
13664                                 break;
13665                         */
13666
13667                         /* Arguments are implicitly global */
13668                         /* Putting R4 vars into registers doesn't work currently */
13669                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13670                         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) {
13671                                 /* 
13672                                  * Make that the variable's liveness interval doesn't contain a call, since
13673                                  * that would cause the lvreg to be spilled, making the whole optimization
13674                                  * useless.
13675                                  */
13676                                 /* This is too slow for JIT compilation */
13677 #if 0
13678                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13679                                         MonoInst *ins;
13680                                         int def_index, call_index, ins_index;
13681                                         gboolean spilled = FALSE;
13682
13683                                         def_index = -1;
13684                                         call_index = -1;
13685                                         ins_index = 0;
13686                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13687                                                 const char *spec = INS_INFO (ins->opcode);
13688
13689                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13690                                                         def_index = ins_index;
13691
13692                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13693                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13694                                                         if (call_index > def_index) {
13695                                                                 spilled = TRUE;
13696                                                                 break;
13697                                                         }
13698                                                 }
13699
13700                                                 if (MONO_IS_CALL (ins))
13701                                                         call_index = ins_index;
13702
13703                                                 ins_index ++;
13704                                         }
13705
13706                                         if (spilled)
13707                                                 break;
13708                                 }
13709 #endif
13710
13711                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13712                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13713                                 var->flags |= MONO_INST_IS_DEAD;
13714                                 cfg->vreg_to_inst [var->dreg] = NULL;
13715                         }
13716                         break;
13717                 }
13718         }
13719
13720         /* 
13721          * Compress the varinfo and vars tables so the liveness computation is faster and
13722          * takes up less space.
13723          */
13724         pos = 0;
13725         for (i = 0; i < cfg->num_varinfo; ++i) {
13726                 MonoInst *var = cfg->varinfo [i];
13727                 if (pos < i && cfg->locals_start == i)
13728                         cfg->locals_start = pos;
13729                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13730                         if (pos < i) {
13731                                 cfg->varinfo [pos] = cfg->varinfo [i];
13732                                 cfg->varinfo [pos]->inst_c0 = pos;
13733                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13734                                 cfg->vars [pos].idx = pos;
13735 #if SIZEOF_REGISTER == 4
13736                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13737                                         /* Modify the two component vars too */
13738                                         MonoInst *var1;
13739
13740                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
13741                                         var1->inst_c0 = pos;
13742                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
13743                                         var1->inst_c0 = pos;
13744                                 }
13745 #endif
13746                         }
13747                         pos ++;
13748                 }
13749         }
13750         cfg->num_varinfo = pos;
13751         if (cfg->locals_start > cfg->num_varinfo)
13752                 cfg->locals_start = cfg->num_varinfo;
13753 }
13754
13755 /*
13756  * mono_allocate_gsharedvt_vars:
13757  *
13758  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
13759  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
13760  */
13761 void
13762 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
13763 {
13764         int i;
13765
13766         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13767
13768         for (i = 0; i < cfg->num_varinfo; ++i) {
13769                 MonoInst *ins = cfg->varinfo [i];
13770                 int idx;
13771
13772                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13773                         if (i >= cfg->locals_start) {
13774                                 /* Local */
13775                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13776                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13777                                 ins->opcode = OP_GSHAREDVT_LOCAL;
13778                                 ins->inst_imm = idx;
13779                         } else {
13780                                 /* Arg */
13781                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
13782                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13783                         }
13784                 }
13785         }
13786 }
13787
13788 /**
13789  * mono_spill_global_vars:
13790  *
13791  *   Generate spill code for variables which are not allocated to registers, 
13792  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13793  * code is generated which could be optimized by the local optimization passes.
13794  */
13795 void
13796 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13797 {
13798         MonoBasicBlock *bb;
13799         char spec2 [16];
13800         int orig_next_vreg;
13801         guint32 *vreg_to_lvreg;
13802         guint32 *lvregs;
13803         guint32 i, lvregs_len;
13804         gboolean dest_has_lvreg = FALSE;
13805         MonoStackType stacktypes [128];
13806         MonoInst **live_range_start, **live_range_end;
13807         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13808
13809         *need_local_opts = FALSE;
13810
13811         memset (spec2, 0, sizeof (spec2));
13812
13813         /* FIXME: Move this function to mini.c */
13814         stacktypes ['i'] = STACK_PTR;
13815         stacktypes ['l'] = STACK_I8;
13816         stacktypes ['f'] = STACK_R8;
13817 #ifdef MONO_ARCH_SIMD_INTRINSICS
13818         stacktypes ['x'] = STACK_VTYPE;
13819 #endif
13820
13821 #if SIZEOF_REGISTER == 4
13822         /* Create MonoInsts for longs */
13823         for (i = 0; i < cfg->num_varinfo; i++) {
13824                 MonoInst *ins = cfg->varinfo [i];
13825
13826                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13827                         switch (ins->type) {
13828                         case STACK_R8:
13829                         case STACK_I8: {
13830                                 MonoInst *tree;
13831
13832                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13833                                         break;
13834
13835                                 g_assert (ins->opcode == OP_REGOFFSET);
13836
13837                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
13838                                 g_assert (tree);
13839                                 tree->opcode = OP_REGOFFSET;
13840                                 tree->inst_basereg = ins->inst_basereg;
13841                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13842
13843                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
13844                                 g_assert (tree);
13845                                 tree->opcode = OP_REGOFFSET;
13846                                 tree->inst_basereg = ins->inst_basereg;
13847                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13848                                 break;
13849                         }
13850                         default:
13851                                 break;
13852                         }
13853                 }
13854         }
13855 #endif
13856
13857         if (cfg->compute_gc_maps) {
13858                 /* registers need liveness info even for !non refs */
13859                 for (i = 0; i < cfg->num_varinfo; i++) {
13860                         MonoInst *ins = cfg->varinfo [i];
13861
13862                         if (ins->opcode == OP_REGVAR)
13863                                 ins->flags |= MONO_INST_GC_TRACK;
13864                 }
13865         }
13866                 
13867         /* FIXME: widening and truncation */
13868
13869         /*
13870          * As an optimization, when a variable allocated to the stack is first loaded into 
13871          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13872          * the variable again.
13873          */
13874         orig_next_vreg = cfg->next_vreg;
13875         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13876         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13877         lvregs_len = 0;
13878
13879         /* 
13880          * These arrays contain the first and last instructions accessing a given
13881          * variable.
13882          * Since we emit bblocks in the same order we process them here, and we
13883          * don't split live ranges, these will precisely describe the live range of
13884          * the variable, i.e. the instruction range where a valid value can be found
13885          * in the variables location.
13886          * The live range is computed using the liveness info computed by the liveness pass.
13887          * We can't use vmv->range, since that is an abstract live range, and we need
13888          * one which is instruction precise.
13889          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13890          */
13891         /* FIXME: Only do this if debugging info is requested */
13892         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13893         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13894         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13895         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13896         
13897         /* Add spill loads/stores */
13898         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13899                 MonoInst *ins;
13900
13901                 if (cfg->verbose_level > 2)
13902                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13903
13904                 /* Clear vreg_to_lvreg array */
13905                 for (i = 0; i < lvregs_len; i++)
13906                         vreg_to_lvreg [lvregs [i]] = 0;
13907                 lvregs_len = 0;
13908
13909                 cfg->cbb = bb;
13910                 MONO_BB_FOR_EACH_INS (bb, ins) {
13911                         const char *spec = INS_INFO (ins->opcode);
13912                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13913                         gboolean store, no_lvreg;
13914                         int sregs [MONO_MAX_SRC_REGS];
13915
13916                         if (G_UNLIKELY (cfg->verbose_level > 2))
13917                                 mono_print_ins (ins);
13918
13919                         if (ins->opcode == OP_NOP)
13920                                 continue;
13921
13922                         /* 
13923                          * We handle LDADDR here as well, since it can only be decomposed
13924                          * when variable addresses are known.
13925                          */
13926                         if (ins->opcode == OP_LDADDR) {
13927                                 MonoInst *var = (MonoInst *)ins->inst_p0;
13928
13929                                 if (var->opcode == OP_VTARG_ADDR) {
13930                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13931                                         MonoInst *vtaddr = var->inst_left;
13932                                         if (vtaddr->opcode == OP_REGVAR) {
13933                                                 ins->opcode = OP_MOVE;
13934                                                 ins->sreg1 = vtaddr->dreg;
13935                                         }
13936                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13937                                                 ins->opcode = OP_LOAD_MEMBASE;
13938                                                 ins->inst_basereg = vtaddr->inst_basereg;
13939                                                 ins->inst_offset = vtaddr->inst_offset;
13940                                         } else
13941                                                 NOT_IMPLEMENTED;
13942                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
13943                                         /* gsharedvt arg passed by ref */
13944                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13945
13946                                         ins->opcode = OP_LOAD_MEMBASE;
13947                                         ins->inst_basereg = var->inst_basereg;
13948                                         ins->inst_offset = var->inst_offset;
13949                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
13950                                         MonoInst *load, *load2, *load3;
13951                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
13952                                         int reg1, reg2, reg3;
13953                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13954                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13955
13956                                         /*
13957                                          * gsharedvt local.
13958                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13959                                          */
13960
13961                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13962
13963                                         g_assert (info_var);
13964                                         g_assert (locals_var);
13965
13966                                         /* Mark the instruction used to compute the locals var as used */
13967                                         cfg->gsharedvt_locals_var_ins = NULL;
13968
13969                                         /* Load the offset */
13970                                         if (info_var->opcode == OP_REGOFFSET) {
13971                                                 reg1 = alloc_ireg (cfg);
13972                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13973                                         } else if (info_var->opcode == OP_REGVAR) {
13974                                                 load = NULL;
13975                                                 reg1 = info_var->dreg;
13976                                         } else {
13977                                                 g_assert_not_reached ();
13978                                         }
13979                                         reg2 = alloc_ireg (cfg);
13980                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13981                                         /* Load the locals area address */
13982                                         reg3 = alloc_ireg (cfg);
13983                                         if (locals_var->opcode == OP_REGOFFSET) {
13984                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13985                                         } else if (locals_var->opcode == OP_REGVAR) {
13986                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13987                                         } else {
13988                                                 g_assert_not_reached ();
13989                                         }
13990                                         /* Compute the address */
13991                                         ins->opcode = OP_PADD;
13992                                         ins->sreg1 = reg3;
13993                                         ins->sreg2 = reg2;
13994
13995                                         mono_bblock_insert_before_ins (bb, ins, load3);
13996                                         mono_bblock_insert_before_ins (bb, load3, load2);
13997                                         if (load)
13998                                                 mono_bblock_insert_before_ins (bb, load2, load);
13999                                 } else {
14000                                         g_assert (var->opcode == OP_REGOFFSET);
14001
14002                                         ins->opcode = OP_ADD_IMM;
14003                                         ins->sreg1 = var->inst_basereg;
14004                                         ins->inst_imm = var->inst_offset;
14005                                 }
14006
14007                                 *need_local_opts = TRUE;
14008                                 spec = INS_INFO (ins->opcode);
14009                         }
14010
14011                         if (ins->opcode < MONO_CEE_LAST) {
14012                                 mono_print_ins (ins);
14013                                 g_assert_not_reached ();
14014                         }
14015
14016                         /*
14017                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14018                          * src register.
14019                          * FIXME:
14020                          */
14021                         if (MONO_IS_STORE_MEMBASE (ins)) {
14022                                 tmp_reg = ins->dreg;
14023                                 ins->dreg = ins->sreg2;
14024                                 ins->sreg2 = tmp_reg;
14025                                 store = TRUE;
14026
14027                                 spec2 [MONO_INST_DEST] = ' ';
14028                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14029                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14030                                 spec2 [MONO_INST_SRC3] = ' ';
14031                                 spec = spec2;
14032                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14033                                 g_assert_not_reached ();
14034                         else
14035                                 store = FALSE;
14036                         no_lvreg = FALSE;
14037
14038                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14039                                 printf ("\t %.3s %d", spec, ins->dreg);
14040                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14041                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14042                                         printf (" %d", sregs [srcindex]);
14043                                 printf ("\n");
14044                         }
14045
14046                         /***************/
14047                         /*    DREG     */
14048                         /***************/
14049                         regtype = spec [MONO_INST_DEST];
14050                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14051                         prev_dreg = -1;
14052
14053                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14054                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14055                                 MonoInst *store_ins;
14056                                 int store_opcode;
14057                                 MonoInst *def_ins = ins;
14058                                 int dreg = ins->dreg; /* The original vreg */
14059
14060                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14061
14062                                 if (var->opcode == OP_REGVAR) {
14063                                         ins->dreg = var->dreg;
14064                                 } 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)) {
14065                                         /* 
14066                                          * Instead of emitting a load+store, use a _membase opcode.
14067                                          */
14068                                         g_assert (var->opcode == OP_REGOFFSET);
14069                                         if (ins->opcode == OP_MOVE) {
14070                                                 NULLIFY_INS (ins);
14071                                                 def_ins = NULL;
14072                                         } else {
14073                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14074                                                 ins->inst_basereg = var->inst_basereg;
14075                                                 ins->inst_offset = var->inst_offset;
14076                                                 ins->dreg = -1;
14077                                         }
14078                                         spec = INS_INFO (ins->opcode);
14079                                 } else {
14080                                         guint32 lvreg;
14081
14082                                         g_assert (var->opcode == OP_REGOFFSET);
14083
14084                                         prev_dreg = ins->dreg;
14085
14086                                         /* Invalidate any previous lvreg for this vreg */
14087                                         vreg_to_lvreg [ins->dreg] = 0;
14088
14089                                         lvreg = 0;
14090
14091                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14092                                                 regtype = 'l';
14093                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14094                                         }
14095
14096                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14097
14098 #if SIZEOF_REGISTER != 8
14099                                         if (regtype == 'l') {
14100                                                 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));
14101                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14102                                                 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));
14103                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14104                                                 def_ins = store_ins;
14105                                         }
14106                                         else
14107 #endif
14108                                         {
14109                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14110
14111                                                 /* Try to fuse the store into the instruction itself */
14112                                                 /* FIXME: Add more instructions */
14113                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14114                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14115                                                         ins->inst_imm = ins->inst_c0;
14116                                                         ins->inst_destbasereg = var->inst_basereg;
14117                                                         ins->inst_offset = var->inst_offset;
14118                                                         spec = INS_INFO (ins->opcode);
14119                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14120                                                         ins->opcode = store_opcode;
14121                                                         ins->inst_destbasereg = var->inst_basereg;
14122                                                         ins->inst_offset = var->inst_offset;
14123
14124                                                         no_lvreg = TRUE;
14125
14126                                                         tmp_reg = ins->dreg;
14127                                                         ins->dreg = ins->sreg2;
14128                                                         ins->sreg2 = tmp_reg;
14129                                                         store = TRUE;
14130
14131                                                         spec2 [MONO_INST_DEST] = ' ';
14132                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14133                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14134                                                         spec2 [MONO_INST_SRC3] = ' ';
14135                                                         spec = spec2;
14136                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14137                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14138                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14139                                                         ins->dreg = -1;
14140                                                         ins->inst_basereg = var->inst_basereg;
14141                                                         ins->inst_offset = var->inst_offset;
14142                                                         spec = INS_INFO (ins->opcode);
14143                                                 } else {
14144                                                         /* printf ("INS: "); mono_print_ins (ins); */
14145                                                         /* Create a store instruction */
14146                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14147
14148                                                         /* Insert it after the instruction */
14149                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14150
14151                                                         def_ins = store_ins;
14152
14153                                                         /* 
14154                                                          * We can't assign ins->dreg to var->dreg here, since the
14155                                                          * sregs could use it. So set a flag, and do it after
14156                                                          * the sregs.
14157                                                          */
14158                                                         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)))
14159                                                                 dest_has_lvreg = TRUE;
14160                                                 }
14161                                         }
14162                                 }
14163
14164                                 if (def_ins && !live_range_start [dreg]) {
14165                                         live_range_start [dreg] = def_ins;
14166                                         live_range_start_bb [dreg] = bb;
14167                                 }
14168
14169                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14170                                         MonoInst *tmp;
14171
14172                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14173                                         tmp->inst_c1 = dreg;
14174                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14175                                 }
14176                         }
14177
14178                         /************/
14179                         /*  SREGS   */
14180                         /************/
14181                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14182                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14183                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14184                                 sreg = sregs [srcindex];
14185
14186                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14187                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14188                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14189                                         MonoInst *use_ins = ins;
14190                                         MonoInst *load_ins;
14191                                         guint32 load_opcode;
14192
14193                                         if (var->opcode == OP_REGVAR) {
14194                                                 sregs [srcindex] = var->dreg;
14195                                                 //mono_inst_set_src_registers (ins, sregs);
14196                                                 live_range_end [sreg] = use_ins;
14197                                                 live_range_end_bb [sreg] = bb;
14198
14199                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14200                                                         MonoInst *tmp;
14201
14202                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14203                                                         /* var->dreg is a hreg */
14204                                                         tmp->inst_c1 = sreg;
14205                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14206                                                 }
14207
14208                                                 continue;
14209                                         }
14210
14211                                         g_assert (var->opcode == OP_REGOFFSET);
14212                                                 
14213                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14214
14215                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14216
14217                                         if (vreg_to_lvreg [sreg]) {
14218                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14219
14220                                                 /* The variable is already loaded to an lvreg */
14221                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14222                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14223                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14224                                                 //mono_inst_set_src_registers (ins, sregs);
14225                                                 continue;
14226                                         }
14227
14228                                         /* Try to fuse the load into the instruction */
14229                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14230                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14231                                                 sregs [0] = var->inst_basereg;
14232                                                 //mono_inst_set_src_registers (ins, sregs);
14233                                                 ins->inst_offset = var->inst_offset;
14234                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14235                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14236                                                 sregs [1] = var->inst_basereg;
14237                                                 //mono_inst_set_src_registers (ins, sregs);
14238                                                 ins->inst_offset = var->inst_offset;
14239                                         } else {
14240                                                 if (MONO_IS_REAL_MOVE (ins)) {
14241                                                         ins->opcode = OP_NOP;
14242                                                         sreg = ins->dreg;
14243                                                 } else {
14244                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14245
14246                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14247
14248                                                         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) {
14249                                                                 if (var->dreg == prev_dreg) {
14250                                                                         /*
14251                                                                          * sreg refers to the value loaded by the load
14252                                                                          * emitted below, but we need to use ins->dreg
14253                                                                          * since it refers to the store emitted earlier.
14254                                                                          */
14255                                                                         sreg = ins->dreg;
14256                                                                 }
14257                                                                 g_assert (sreg != -1);
14258                                                                 vreg_to_lvreg [var->dreg] = sreg;
14259                                                                 g_assert (lvregs_len < 1024);
14260                                                                 lvregs [lvregs_len ++] = var->dreg;
14261                                                         }
14262                                                 }
14263
14264                                                 sregs [srcindex] = sreg;
14265                                                 //mono_inst_set_src_registers (ins, sregs);
14266
14267 #if SIZEOF_REGISTER != 8
14268                                                 if (regtype == 'l') {
14269                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14270                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14271                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14272                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14273                                                         use_ins = load_ins;
14274                                                 }
14275                                                 else
14276 #endif
14277                                                 {
14278 #if SIZEOF_REGISTER == 4
14279                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14280 #endif
14281                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14282                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14283                                                         use_ins = load_ins;
14284                                                 }
14285                                         }
14286
14287                                         if (var->dreg < orig_next_vreg) {
14288                                                 live_range_end [var->dreg] = use_ins;
14289                                                 live_range_end_bb [var->dreg] = bb;
14290                                         }
14291
14292                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14293                                                 MonoInst *tmp;
14294
14295                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14296                                                 tmp->inst_c1 = var->dreg;
14297                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14298                                         }
14299                                 }
14300                         }
14301                         mono_inst_set_src_registers (ins, sregs);
14302
14303                         if (dest_has_lvreg) {
14304                                 g_assert (ins->dreg != -1);
14305                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14306                                 g_assert (lvregs_len < 1024);
14307                                 lvregs [lvregs_len ++] = prev_dreg;
14308                                 dest_has_lvreg = FALSE;
14309                         }
14310
14311                         if (store) {
14312                                 tmp_reg = ins->dreg;
14313                                 ins->dreg = ins->sreg2;
14314                                 ins->sreg2 = tmp_reg;
14315                         }
14316
14317                         if (MONO_IS_CALL (ins)) {
14318                                 /* Clear vreg_to_lvreg array */
14319                                 for (i = 0; i < lvregs_len; i++)
14320                                         vreg_to_lvreg [lvregs [i]] = 0;
14321                                 lvregs_len = 0;
14322                         } else if (ins->opcode == OP_NOP) {
14323                                 ins->dreg = -1;
14324                                 MONO_INST_NULLIFY_SREGS (ins);
14325                         }
14326
14327                         if (cfg->verbose_level > 2)
14328                                 mono_print_ins_index (1, ins);
14329                 }
14330
14331                 /* Extend the live range based on the liveness info */
14332                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14333                         for (i = 0; i < cfg->num_varinfo; i ++) {
14334                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14335
14336                                 if (vreg_is_volatile (cfg, vi->vreg))
14337                                         /* The liveness info is incomplete */
14338                                         continue;
14339
14340                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14341                                         /* Live from at least the first ins of this bb */
14342                                         live_range_start [vi->vreg] = bb->code;
14343                                         live_range_start_bb [vi->vreg] = bb;
14344                                 }
14345
14346                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14347                                         /* Live at least until the last ins of this bb */
14348                                         live_range_end [vi->vreg] = bb->last_ins;
14349                                         live_range_end_bb [vi->vreg] = bb;
14350                                 }
14351                         }
14352                 }
14353         }
14354         
14355         /*
14356          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14357          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14358          */
14359         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14360                 for (i = 0; i < cfg->num_varinfo; ++i) {
14361                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14362                         MonoInst *ins;
14363
14364                         if (live_range_start [vreg]) {
14365                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14366                                 ins->inst_c0 = i;
14367                                 ins->inst_c1 = vreg;
14368                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14369                         }
14370                         if (live_range_end [vreg]) {
14371                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14372                                 ins->inst_c0 = i;
14373                                 ins->inst_c1 = vreg;
14374                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14375                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14376                                 else
14377                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14378                         }
14379                 }
14380         }
14381
14382         if (cfg->gsharedvt_locals_var_ins) {
14383                 /* Nullify if unused */
14384                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14385                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14386         }
14387
14388         g_free (live_range_start);
14389         g_free (live_range_end);
14390         g_free (live_range_start_bb);
14391         g_free (live_range_end_bb);
14392 }
14393
14394
14395 /**
14396  * FIXME:
14397  * - use 'iadd' instead of 'int_add'
14398  * - handling ovf opcodes: decompose in method_to_ir.
14399  * - unify iregs/fregs
14400  *   -> partly done, the missing parts are:
14401  *   - a more complete unification would involve unifying the hregs as well, so
14402  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14403  *     would no longer map to the machine hregs, so the code generators would need to
14404  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14405  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14406  *     fp/non-fp branches speeds it up by about 15%.
14407  * - use sext/zext opcodes instead of shifts
14408  * - add OP_ICALL
14409  * - get rid of TEMPLOADs if possible and use vregs instead
14410  * - clean up usage of OP_P/OP_ opcodes
14411  * - cleanup usage of DUMMY_USE
14412  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14413  *   stack
14414  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14415  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14416  * - make sure handle_stack_args () is called before the branch is emitted
14417  * - when the new IR is done, get rid of all unused stuff
14418  * - COMPARE/BEQ as separate instructions or unify them ?
14419  *   - keeping them separate allows specialized compare instructions like
14420  *     compare_imm, compare_membase
14421  *   - most back ends unify fp compare+branch, fp compare+ceq
14422  * - integrate mono_save_args into inline_method
14423  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14424  * - handle long shift opts on 32 bit platforms somehow: they require 
14425  *   3 sregs (2 for arg1 and 1 for arg2)
14426  * - make byref a 'normal' type.
14427  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14428  *   variable if needed.
14429  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14430  *   like inline_method.
14431  * - remove inlining restrictions
14432  * - fix LNEG and enable cfold of INEG
14433  * - generalize x86 optimizations like ldelema as a peephole optimization
14434  * - add store_mem_imm for amd64
14435  * - optimize the loading of the interruption flag in the managed->native wrappers
14436  * - avoid special handling of OP_NOP in passes
14437  * - move code inserting instructions into one function/macro.
14438  * - try a coalescing phase after liveness analysis
14439  * - add float -> vreg conversion + local optimizations on !x86
14440  * - figure out how to handle decomposed branches during optimizations, ie.
14441  *   compare+branch, op_jump_table+op_br etc.
14442  * - promote RuntimeXHandles to vregs
14443  * - vtype cleanups:
14444  *   - add a NEW_VARLOADA_VREG macro
14445  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14446  *   accessing vtype fields.
14447  * - get rid of I8CONST on 64 bit platforms
14448  * - dealing with the increase in code size due to branches created during opcode
14449  *   decomposition:
14450  *   - use extended basic blocks
14451  *     - all parts of the JIT
14452  *     - handle_global_vregs () && local regalloc
14453  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14454  * - sources of increase in code size:
14455  *   - vtypes
14456  *   - long compares
14457  *   - isinst and castclass
14458  *   - lvregs not allocated to global registers even if used multiple times
14459  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14460  *   meaningful.
14461  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14462  * - add all micro optimizations from the old JIT
14463  * - put tree optimizations into the deadce pass
14464  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14465  *   specific function.
14466  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14467  *   fcompare + branchCC.
14468  * - create a helper function for allocating a stack slot, taking into account 
14469  *   MONO_CFG_HAS_SPILLUP.
14470  * - merge r68207.
14471  * - merge the ia64 switch changes.
14472  * - optimize mono_regstate2_alloc_int/float.
14473  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14474  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14475  *   parts of the tree could be separated by other instructions, killing the tree
14476  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14477  *   instructions if the result of the load is used multiple times ?
14478  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14479  * - LAST MERGE: 108395.
14480  * - when returning vtypes in registers, generate IR and append it to the end of the
14481  *   last bb instead of doing it in the epilog.
14482  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14483  */
14484
14485 /*
14486
14487 NOTES
14488 -----
14489
14490 - When to decompose opcodes:
14491   - earlier: this makes some optimizations hard to implement, since the low level IR
14492   no longer contains the neccessary information. But it is easier to do.
14493   - later: harder to implement, enables more optimizations.
14494 - Branches inside bblocks:
14495   - created when decomposing complex opcodes. 
14496     - branches to another bblock: harmless, but not tracked by the branch 
14497       optimizations, so need to branch to a label at the start of the bblock.
14498     - branches to inside the same bblock: very problematic, trips up the local
14499       reg allocator. Can be fixed by spitting the current bblock, but that is a
14500       complex operation, since some local vregs can become global vregs etc.
14501 - Local/global vregs:
14502   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14503     local register allocator.
14504   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14505     structure, created by mono_create_var (). Assigned to hregs or the stack by
14506     the global register allocator.
14507 - When to do optimizations like alu->alu_imm:
14508   - earlier -> saves work later on since the IR will be smaller/simpler
14509   - later -> can work on more instructions
14510 - Handling of valuetypes:
14511   - When a vtype is pushed on the stack, a new temporary is created, an 
14512     instruction computing its address (LDADDR) is emitted and pushed on
14513     the stack. Need to optimize cases when the vtype is used immediately as in
14514     argument passing, stloc etc.
14515 - Instead of the to_end stuff in the old JIT, simply call the function handling
14516   the values on the stack before emitting the last instruction of the bb.
14517 */
14518
14519 #else /* !DISABLE_JIT */
14520
14521 MONO_EMPTY_SOURCE_FILE (method_to_ir);
14522
14523 #endif /* !DISABLE_JIT */