Merge pull request #4009 from kumpera/lazy-array-ifaces
[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 /* helper methods signatures */
156 static MonoMethodSignature *helper_sig_domain_get;
157 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
158 static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline;
159
160 /* type loading helpers */
161 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
162 static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, System.Diagnostics, DebuggableAttribute)
163
164 /*
165  * Instruction metadata
166  */
167 #ifdef MINI_OP
168 #undef MINI_OP
169 #endif
170 #ifdef MINI_OP3
171 #undef MINI_OP3
172 #endif
173 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
174 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
175 #define NONE ' '
176 #define IREG 'i'
177 #define FREG 'f'
178 #define VREG 'v'
179 #define XREG 'x'
180 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
181 #define LREG IREG
182 #else
183 #define LREG 'l'
184 #endif
185 /* keep in sync with the enum in mini.h */
186 const char
187 ins_info[] = {
188 #include "mini-ops.h"
189 };
190 #undef MINI_OP
191 #undef MINI_OP3
192
193 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
194 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
195 /* 
196  * This should contain the index of the last sreg + 1. This is not the same
197  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
198  */
199 const gint8 ins_sreg_counts[] = {
200 #include "mini-ops.h"
201 };
202 #undef MINI_OP
203 #undef MINI_OP3
204
205 #define MONO_INIT_VARINFO(vi,id) do { \
206         (vi)->range.first_use.pos.bid = 0xffff; \
207         (vi)->reg = -1; \
208         (vi)->idx = (id); \
209 } while (0)
210
211 guint32
212 mono_alloc_ireg (MonoCompile *cfg)
213 {
214         return alloc_ireg (cfg);
215 }
216
217 guint32
218 mono_alloc_lreg (MonoCompile *cfg)
219 {
220         return alloc_lreg (cfg);
221 }
222
223 guint32
224 mono_alloc_freg (MonoCompile *cfg)
225 {
226         return alloc_freg (cfg);
227 }
228
229 guint32
230 mono_alloc_preg (MonoCompile *cfg)
231 {
232         return alloc_preg (cfg);
233 }
234
235 guint32
236 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
237 {
238         return alloc_dreg (cfg, stack_type);
239 }
240
241 /*
242  * mono_alloc_ireg_ref:
243  *
244  *   Allocate an IREG, and mark it as holding a GC ref.
245  */
246 guint32
247 mono_alloc_ireg_ref (MonoCompile *cfg)
248 {
249         return alloc_ireg_ref (cfg);
250 }
251
252 /*
253  * mono_alloc_ireg_mp:
254  *
255  *   Allocate an IREG, and mark it as holding a managed pointer.
256  */
257 guint32
258 mono_alloc_ireg_mp (MonoCompile *cfg)
259 {
260         return alloc_ireg_mp (cfg);
261 }
262
263 /*
264  * mono_alloc_ireg_copy:
265  *
266  *   Allocate an IREG with the same GC type as VREG.
267  */
268 guint32
269 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
270 {
271         if (vreg_is_ref (cfg, vreg))
272                 return alloc_ireg_ref (cfg);
273         else if (vreg_is_mp (cfg, vreg))
274                 return alloc_ireg_mp (cfg);
275         else
276                 return alloc_ireg (cfg);
277 }
278
279 guint
280 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
281 {
282         if (type->byref)
283                 return OP_MOVE;
284
285         type = mini_get_underlying_type (type);
286 handle_enum:
287         switch (type->type) {
288         case MONO_TYPE_I1:
289         case MONO_TYPE_U1:
290                 return OP_MOVE;
291         case MONO_TYPE_I2:
292         case MONO_TYPE_U2:
293                 return OP_MOVE;
294         case MONO_TYPE_I4:
295         case MONO_TYPE_U4:
296                 return OP_MOVE;
297         case MONO_TYPE_I:
298         case MONO_TYPE_U:
299         case MONO_TYPE_PTR:
300         case MONO_TYPE_FNPTR:
301                 return OP_MOVE;
302         case MONO_TYPE_CLASS:
303         case MONO_TYPE_STRING:
304         case MONO_TYPE_OBJECT:
305         case MONO_TYPE_SZARRAY:
306         case MONO_TYPE_ARRAY:    
307                 return OP_MOVE;
308         case MONO_TYPE_I8:
309         case MONO_TYPE_U8:
310 #if SIZEOF_REGISTER == 8
311                 return OP_MOVE;
312 #else
313                 return OP_LMOVE;
314 #endif
315         case MONO_TYPE_R4:
316                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
317         case MONO_TYPE_R8:
318                 return OP_FMOVE;
319         case MONO_TYPE_VALUETYPE:
320                 if (type->data.klass->enumtype) {
321                         type = mono_class_enum_basetype (type->data.klass);
322                         goto handle_enum;
323                 }
324                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
325                         return OP_XMOVE;
326                 return OP_VMOVE;
327         case MONO_TYPE_TYPEDBYREF:
328                 return OP_VMOVE;
329         case MONO_TYPE_GENERICINST:
330                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
331                         return OP_XMOVE;
332                 type = &type->data.generic_class->container_class->byval_arg;
333                 goto handle_enum;
334         case MONO_TYPE_VAR:
335         case MONO_TYPE_MVAR:
336                 g_assert (cfg->gshared);
337                 if (mini_type_var_is_vt (type))
338                         return OP_VMOVE;
339                 else
340                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
341         default:
342                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
343         }
344         return -1;
345 }
346
347 void
348 mono_print_bb (MonoBasicBlock *bb, const char *msg)
349 {
350         int i;
351         MonoInst *tree;
352
353         printf ("\n%s %d: [IN: ", msg, bb->block_num);
354         for (i = 0; i < bb->in_count; ++i)
355                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
356         printf (", OUT: ");
357         for (i = 0; i < bb->out_count; ++i)
358                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
359         printf (" ]\n");
360         for (tree = bb->code; tree; tree = tree->next)
361                 mono_print_ins_index (-1, tree);
362 }
363
364 void
365 mono_create_helper_signatures (void)
366 {
367         helper_sig_domain_get = mono_create_icall_signature ("ptr");
368         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
369         helper_sig_llvmonly_imt_trampoline = mono_create_icall_signature ("ptr ptr ptr");
370 }
371
372 static MONO_NEVER_INLINE void
373 break_on_unverified (void)
374 {
375         if (mini_get_debug_options ()->break_on_unverified)
376                 G_BREAKPOINT ();
377 }
378
379 static MONO_NEVER_INLINE void
380 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
381 {
382         char *method_fname = mono_method_full_name (method, TRUE);
383         char *field_fname = mono_field_full_name (field);
384         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
385         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
386         g_free (method_fname);
387         g_free (field_fname);
388 }
389
390 static MONO_NEVER_INLINE void
391 inline_failure (MonoCompile *cfg, const char *msg)
392 {
393         if (cfg->verbose_level >= 2)
394                 printf ("inline failed: %s\n", msg);
395         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
396 }
397
398 static MONO_NEVER_INLINE void
399 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
400 {
401         if (cfg->verbose_level > 2)                                                                                     \
402                 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);
403         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
404 }
405
406 static MONO_NEVER_INLINE void
407 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
408 {
409         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);
410         if (cfg->verbose_level >= 2)
411                 printf ("%s\n", cfg->exception_message);
412         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
413 }
414
415 /*
416  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
417  * foo<T> (int i) { ldarg.0; box T; }
418  */
419 #define UNVERIFIED do { \
420         if (cfg->gsharedvt) { \
421                 if (cfg->verbose_level > 2)                                                                     \
422                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
423                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
424                 goto exception_exit;                                                                                    \
425         }                                                                                                                                       \
426         break_on_unverified ();                                                                                         \
427         goto unverified;                                                                                                        \
428 } while (0)
429
430 #define GET_BBLOCK(cfg,tblock,ip) do {  \
431                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
432                 if (!(tblock)) {        \
433                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
434             NEW_BBLOCK (cfg, (tblock)); \
435                         (tblock)->cil_code = (ip);      \
436                         ADD_BBLOCK (cfg, (tblock));     \
437                 } \
438         } while (0)
439
440 #if defined(TARGET_X86) || defined(TARGET_AMD64)
441 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
442                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
443                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
444                 (dest)->sreg1 = (sr1); \
445                 (dest)->sreg2 = (sr2); \
446                 (dest)->inst_imm = (imm); \
447                 (dest)->backend.shift_amount = (shift); \
448                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
449         } while (0)
450 #endif
451
452 /* Emit conversions so both operands of a binary opcode are of the same type */
453 static void
454 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
455 {
456         MonoInst *arg1 = *arg1_ref;
457         MonoInst *arg2 = *arg2_ref;
458
459         if (cfg->r4fp &&
460                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
461                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
462                 MonoInst *conv;
463
464                 /* Mixing r4/r8 is allowed by the spec */
465                 if (arg1->type == STACK_R4) {
466                         int dreg = alloc_freg (cfg);
467
468                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
469                         conv->type = STACK_R8;
470                         ins->sreg1 = dreg;
471                         *arg1_ref = conv;
472                 }
473                 if (arg2->type == STACK_R4) {
474                         int dreg = alloc_freg (cfg);
475
476                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
477                         conv->type = STACK_R8;
478                         ins->sreg2 = dreg;
479                         *arg2_ref = conv;
480                 }
481         }
482
483 #if SIZEOF_REGISTER == 8
484         /* FIXME: Need to add many more cases */
485         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
486                 MonoInst *widen;
487
488                 int dr = alloc_preg (cfg);
489                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
490                 (ins)->sreg2 = widen->dreg;
491         }
492 #endif
493 }
494
495 #define ADD_BINOP(op) do {      \
496                 MONO_INST_NEW (cfg, ins, (op)); \
497                 sp -= 2;        \
498                 ins->sreg1 = sp [0]->dreg;      \
499                 ins->sreg2 = sp [1]->dreg;      \
500                 type_from_op (cfg, ins, sp [0], sp [1]);        \
501                 CHECK_TYPE (ins);       \
502                 /* Have to insert a widening op */               \
503         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
504         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
505         MONO_ADD_INS ((cfg)->cbb, (ins)); \
506         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
507         } while (0)
508
509 #define ADD_UNOP(op) do {       \
510                 MONO_INST_NEW (cfg, ins, (op)); \
511                 sp--;   \
512                 ins->sreg1 = sp [0]->dreg;      \
513                 type_from_op (cfg, ins, sp [0], NULL);  \
514                 CHECK_TYPE (ins);       \
515         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
516         MONO_ADD_INS ((cfg)->cbb, (ins)); \
517                 *sp++ = mono_decompose_opcode (cfg, ins);       \
518         } while (0)
519
520 #define ADD_BINCOND(next_block) do {    \
521                 MonoInst *cmp;  \
522                 sp -= 2; \
523                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
524                 cmp->sreg1 = sp [0]->dreg;      \
525                 cmp->sreg2 = sp [1]->dreg;      \
526                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
527                 CHECK_TYPE (cmp);       \
528                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
529                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
530                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
531                 GET_BBLOCK (cfg, tblock, target);               \
532                 link_bblock (cfg, cfg->cbb, tblock);    \
533                 ins->inst_true_bb = tblock;     \
534                 if ((next_block)) {     \
535                         link_bblock (cfg, cfg->cbb, (next_block));      \
536                         ins->inst_false_bb = (next_block);      \
537                         start_new_bblock = 1;   \
538                 } else {        \
539                         GET_BBLOCK (cfg, tblock, ip);           \
540                         link_bblock (cfg, cfg->cbb, tblock);    \
541                         ins->inst_false_bb = tblock;    \
542                         start_new_bblock = 2;   \
543                 }       \
544                 if (sp != stack_start) {                                                                        \
545                     handle_stack_args (cfg, stack_start, sp - stack_start); \
546                         CHECK_UNVERIFIABLE (cfg); \
547                 } \
548         MONO_ADD_INS (cfg->cbb, cmp); \
549                 MONO_ADD_INS (cfg->cbb, ins);   \
550         } while (0)
551
552 /* *
553  * link_bblock: Links two basic blocks
554  *
555  * links two basic blocks in the control flow graph, the 'from'
556  * argument is the starting block and the 'to' argument is the block
557  * the control flow ends to after 'from'.
558  */
559 static void
560 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
561 {
562         MonoBasicBlock **newa;
563         int i, found;
564
565 #if 0
566         if (from->cil_code) {
567                 if (to->cil_code)
568                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
569                 else
570                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
571         } else {
572                 if (to->cil_code)
573                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
574                 else
575                         printf ("edge from entry to exit\n");
576         }
577 #endif
578
579         found = FALSE;
580         for (i = 0; i < from->out_count; ++i) {
581                 if (to == from->out_bb [i]) {
582                         found = TRUE;
583                         break;
584                 }
585         }
586         if (!found) {
587                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
588                 for (i = 0; i < from->out_count; ++i) {
589                         newa [i] = from->out_bb [i];
590                 }
591                 newa [i] = to;
592                 from->out_count++;
593                 from->out_bb = newa;
594         }
595
596         found = FALSE;
597         for (i = 0; i < to->in_count; ++i) {
598                 if (from == to->in_bb [i]) {
599                         found = TRUE;
600                         break;
601                 }
602         }
603         if (!found) {
604                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
605                 for (i = 0; i < to->in_count; ++i) {
606                         newa [i] = to->in_bb [i];
607                 }
608                 newa [i] = from;
609                 to->in_count++;
610                 to->in_bb = newa;
611         }
612 }
613
614 void
615 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
616 {
617         link_bblock (cfg, from, to);
618 }
619
620 /**
621  * mono_find_block_region:
622  *
623  *   We mark each basic block with a region ID. We use that to avoid BB
624  *   optimizations when blocks are in different regions.
625  *
626  * Returns:
627  *   A region token that encodes where this region is, and information
628  *   about the clause owner for this block.
629  *
630  *   The region encodes the try/catch/filter clause that owns this block
631  *   as well as the type.  -1 is a special value that represents a block
632  *   that is in none of try/catch/filter.
633  */
634 static int
635 mono_find_block_region (MonoCompile *cfg, int offset)
636 {
637         MonoMethodHeader *header = cfg->header;
638         MonoExceptionClause *clause;
639         int i;
640
641         for (i = 0; i < header->num_clauses; ++i) {
642                 clause = &header->clauses [i];
643                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
644                     (offset < (clause->handler_offset)))
645                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
646                            
647                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
648                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
649                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
650                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
651                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
652                         else
653                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
654                 }
655         }
656         for (i = 0; i < header->num_clauses; ++i) {
657                 clause = &header->clauses [i];
658
659                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
660                         return ((i + 1) << 8) | clause->flags;
661         }
662
663         return -1;
664 }
665
666 static gboolean
667 ip_in_finally_clause (MonoCompile *cfg, int offset)
668 {
669         MonoMethodHeader *header = cfg->header;
670         MonoExceptionClause *clause;
671         int i;
672
673         for (i = 0; i < header->num_clauses; ++i) {
674                 clause = &header->clauses [i];
675                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
676                         continue;
677
678                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
679                         return TRUE;
680         }
681         return FALSE;
682 }
683
684 static GList*
685 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
686 {
687         MonoMethodHeader *header = cfg->header;
688         MonoExceptionClause *clause;
689         int i;
690         GList *res = NULL;
691
692         for (i = 0; i < header->num_clauses; ++i) {
693                 clause = &header->clauses [i];
694                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
695                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
696                         if (clause->flags == type)
697                                 res = g_list_append (res, clause);
698                 }
699         }
700         return res;
701 }
702
703 static void
704 mono_create_spvar_for_region (MonoCompile *cfg, int region)
705 {
706         MonoInst *var;
707
708         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
709         if (var)
710                 return;
711
712         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
713         /* prevent it from being register allocated */
714         var->flags |= MONO_INST_VOLATILE;
715
716         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
717 }
718
719 MonoInst *
720 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
721 {
722         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
723 }
724
725 static MonoInst*
726 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
727 {
728         MonoInst *var;
729
730         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
731         if (var)
732                 return var;
733
734         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
735         /* prevent it from being register allocated */
736         var->flags |= MONO_INST_VOLATILE;
737
738         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
739
740         return var;
741 }
742
743 /*
744  * Returns the type used in the eval stack when @type is loaded.
745  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
746  */
747 void
748 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
749 {
750         MonoClass *klass;
751
752         type = mini_get_underlying_type (type);
753         inst->klass = klass = mono_class_from_mono_type (type);
754         if (type->byref) {
755                 inst->type = STACK_MP;
756                 return;
757         }
758
759 handle_enum:
760         switch (type->type) {
761         case MONO_TYPE_VOID:
762                 inst->type = STACK_INV;
763                 return;
764         case MONO_TYPE_I1:
765         case MONO_TYPE_U1:
766         case MONO_TYPE_I2:
767         case MONO_TYPE_U2:
768         case MONO_TYPE_I4:
769         case MONO_TYPE_U4:
770                 inst->type = STACK_I4;
771                 return;
772         case MONO_TYPE_I:
773         case MONO_TYPE_U:
774         case MONO_TYPE_PTR:
775         case MONO_TYPE_FNPTR:
776                 inst->type = STACK_PTR;
777                 return;
778         case MONO_TYPE_CLASS:
779         case MONO_TYPE_STRING:
780         case MONO_TYPE_OBJECT:
781         case MONO_TYPE_SZARRAY:
782         case MONO_TYPE_ARRAY:    
783                 inst->type = STACK_OBJ;
784                 return;
785         case MONO_TYPE_I8:
786         case MONO_TYPE_U8:
787                 inst->type = STACK_I8;
788                 return;
789         case MONO_TYPE_R4:
790                 inst->type = cfg->r4_stack_type;
791                 break;
792         case MONO_TYPE_R8:
793                 inst->type = STACK_R8;
794                 return;
795         case MONO_TYPE_VALUETYPE:
796                 if (type->data.klass->enumtype) {
797                         type = mono_class_enum_basetype (type->data.klass);
798                         goto handle_enum;
799                 } else {
800                         inst->klass = klass;
801                         inst->type = STACK_VTYPE;
802                         return;
803                 }
804         case MONO_TYPE_TYPEDBYREF:
805                 inst->klass = mono_defaults.typed_reference_class;
806                 inst->type = STACK_VTYPE;
807                 return;
808         case MONO_TYPE_GENERICINST:
809                 type = &type->data.generic_class->container_class->byval_arg;
810                 goto handle_enum;
811         case MONO_TYPE_VAR:
812         case MONO_TYPE_MVAR:
813                 g_assert (cfg->gshared);
814                 if (mini_is_gsharedvt_type (type)) {
815                         g_assert (cfg->gsharedvt);
816                         inst->type = STACK_VTYPE;
817                 } else {
818                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
819                 }
820                 return;
821         default:
822                 g_error ("unknown type 0x%02x in eval stack type", type->type);
823         }
824 }
825
826 /*
827  * The following tables are used to quickly validate the IL code in type_from_op ().
828  */
829 static const char
830 bin_num_table [STACK_MAX] [STACK_MAX] = {
831         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
833         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
834         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
835         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
836         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
837         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
838         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
839         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
840 };
841
842 static const char 
843 neg_table [] = {
844         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
845 };
846
847 /* reduce the size of this table */
848 static const char
849 bin_int_table [STACK_MAX] [STACK_MAX] = {
850         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
851         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
852         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
853         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
854         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
855         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
856         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
857         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
858 };
859
860 static const char
861 bin_comp_table [STACK_MAX] [STACK_MAX] = {
862 /*      Inv i  L  p  F  &  O  vt r4 */
863         {0},
864         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
865         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
866         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
867         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
868         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
869         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
870         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
871         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
872 };
873
874 /* reduce the size of this table */
875 static const char
876 shift_table [STACK_MAX] [STACK_MAX] = {
877         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
878         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
879         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
880         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
881         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
882         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
883         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
884         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
885 };
886
887 /*
888  * Tables to map from the non-specific opcode to the matching
889  * type-specific opcode.
890  */
891 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
892 static const guint16
893 binops_op_map [STACK_MAX] = {
894         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
895 };
896
897 /* handles from CEE_NEG to CEE_CONV_U8 */
898 static const guint16
899 unops_op_map [STACK_MAX] = {
900         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
901 };
902
903 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
904 static const guint16
905 ovfops_op_map [STACK_MAX] = {
906         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
907 };
908
909 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
910 static const guint16
911 ovf2ops_op_map [STACK_MAX] = {
912         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
913 };
914
915 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
916 static const guint16
917 ovf3ops_op_map [STACK_MAX] = {
918         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
919 };
920
921 /* handles from CEE_BEQ to CEE_BLT_UN */
922 static const guint16
923 beqops_op_map [STACK_MAX] = {
924         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
925 };
926
927 /* handles from CEE_CEQ to CEE_CLT_UN */
928 static const guint16
929 ceqops_op_map [STACK_MAX] = {
930         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
931 };
932
933 /*
934  * Sets ins->type (the type on the eval stack) according to the
935  * type of the opcode and the arguments to it.
936  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
937  *
938  * FIXME: this function sets ins->type unconditionally in some cases, but
939  * it should set it to invalid for some types (a conv.x on an object)
940  */
941 static void
942 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
943 {
944         switch (ins->opcode) {
945         /* binops */
946         case CEE_ADD:
947         case CEE_SUB:
948         case CEE_MUL:
949         case CEE_DIV:
950         case CEE_REM:
951                 /* FIXME: check unverifiable args for STACK_MP */
952                 ins->type = bin_num_table [src1->type] [src2->type];
953                 ins->opcode += binops_op_map [ins->type];
954                 break;
955         case CEE_DIV_UN:
956         case CEE_REM_UN:
957         case CEE_AND:
958         case CEE_OR:
959         case CEE_XOR:
960                 ins->type = bin_int_table [src1->type] [src2->type];
961                 ins->opcode += binops_op_map [ins->type];
962                 break;
963         case CEE_SHL:
964         case CEE_SHR:
965         case CEE_SHR_UN:
966                 ins->type = shift_table [src1->type] [src2->type];
967                 ins->opcode += binops_op_map [ins->type];
968                 break;
969         case OP_COMPARE:
970         case OP_LCOMPARE:
971         case OP_ICOMPARE:
972                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
973                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
974                         ins->opcode = OP_LCOMPARE;
975                 else if (src1->type == STACK_R4)
976                         ins->opcode = OP_RCOMPARE;
977                 else if (src1->type == STACK_R8)
978                         ins->opcode = OP_FCOMPARE;
979                 else
980                         ins->opcode = OP_ICOMPARE;
981                 break;
982         case OP_ICOMPARE_IMM:
983                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
984                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
985                         ins->opcode = OP_LCOMPARE_IMM;          
986                 break;
987         case CEE_BEQ:
988         case CEE_BGE:
989         case CEE_BGT:
990         case CEE_BLE:
991         case CEE_BLT:
992         case CEE_BNE_UN:
993         case CEE_BGE_UN:
994         case CEE_BGT_UN:
995         case CEE_BLE_UN:
996         case CEE_BLT_UN:
997                 ins->opcode += beqops_op_map [src1->type];
998                 break;
999         case OP_CEQ:
1000                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
1001                 ins->opcode += ceqops_op_map [src1->type];
1002                 break;
1003         case OP_CGT:
1004         case OP_CGT_UN:
1005         case OP_CLT:
1006         case OP_CLT_UN:
1007                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
1008                 ins->opcode += ceqops_op_map [src1->type];
1009                 break;
1010         /* unops */
1011         case CEE_NEG:
1012                 ins->type = neg_table [src1->type];
1013                 ins->opcode += unops_op_map [ins->type];
1014                 break;
1015         case CEE_NOT:
1016                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1017                         ins->type = src1->type;
1018                 else
1019                         ins->type = STACK_INV;
1020                 ins->opcode += unops_op_map [ins->type];
1021                 break;
1022         case CEE_CONV_I1:
1023         case CEE_CONV_I2:
1024         case CEE_CONV_I4:
1025         case CEE_CONV_U4:
1026                 ins->type = STACK_I4;
1027                 ins->opcode += unops_op_map [src1->type];
1028                 break;
1029         case CEE_CONV_R_UN:
1030                 ins->type = STACK_R8;
1031                 switch (src1->type) {
1032                 case STACK_I4:
1033                 case STACK_PTR:
1034                         ins->opcode = OP_ICONV_TO_R_UN;
1035                         break;
1036                 case STACK_I8:
1037                         ins->opcode = OP_LCONV_TO_R_UN; 
1038                         break;
1039                 }
1040                 break;
1041         case CEE_CONV_OVF_I1:
1042         case CEE_CONV_OVF_U1:
1043         case CEE_CONV_OVF_I2:
1044         case CEE_CONV_OVF_U2:
1045         case CEE_CONV_OVF_I4:
1046         case CEE_CONV_OVF_U4:
1047                 ins->type = STACK_I4;
1048                 ins->opcode += ovf3ops_op_map [src1->type];
1049                 break;
1050         case CEE_CONV_OVF_I_UN:
1051         case CEE_CONV_OVF_U_UN:
1052                 ins->type = STACK_PTR;
1053                 ins->opcode += ovf2ops_op_map [src1->type];
1054                 break;
1055         case CEE_CONV_OVF_I1_UN:
1056         case CEE_CONV_OVF_I2_UN:
1057         case CEE_CONV_OVF_I4_UN:
1058         case CEE_CONV_OVF_U1_UN:
1059         case CEE_CONV_OVF_U2_UN:
1060         case CEE_CONV_OVF_U4_UN:
1061                 ins->type = STACK_I4;
1062                 ins->opcode += ovf2ops_op_map [src1->type];
1063                 break;
1064         case CEE_CONV_U:
1065                 ins->type = STACK_PTR;
1066                 switch (src1->type) {
1067                 case STACK_I4:
1068                         ins->opcode = OP_ICONV_TO_U;
1069                         break;
1070                 case STACK_PTR:
1071                 case STACK_MP:
1072 #if SIZEOF_VOID_P == 8
1073                         ins->opcode = OP_LCONV_TO_U;
1074 #else
1075                         ins->opcode = OP_MOVE;
1076 #endif
1077                         break;
1078                 case STACK_I8:
1079                         ins->opcode = OP_LCONV_TO_U;
1080                         break;
1081                 case STACK_R8:
1082                         ins->opcode = OP_FCONV_TO_U;
1083                         break;
1084                 }
1085                 break;
1086         case CEE_CONV_I8:
1087         case CEE_CONV_U8:
1088                 ins->type = STACK_I8;
1089                 ins->opcode += unops_op_map [src1->type];
1090                 break;
1091         case CEE_CONV_OVF_I8:
1092         case CEE_CONV_OVF_U8:
1093                 ins->type = STACK_I8;
1094                 ins->opcode += ovf3ops_op_map [src1->type];
1095                 break;
1096         case CEE_CONV_OVF_U8_UN:
1097         case CEE_CONV_OVF_I8_UN:
1098                 ins->type = STACK_I8;
1099                 ins->opcode += ovf2ops_op_map [src1->type];
1100                 break;
1101         case CEE_CONV_R4:
1102                 ins->type = cfg->r4_stack_type;
1103                 ins->opcode += unops_op_map [src1->type];
1104                 break;
1105         case CEE_CONV_R8:
1106                 ins->type = STACK_R8;
1107                 ins->opcode += unops_op_map [src1->type];
1108                 break;
1109         case OP_CKFINITE:
1110                 ins->type = STACK_R8;           
1111                 break;
1112         case CEE_CONV_U2:
1113         case CEE_CONV_U1:
1114                 ins->type = STACK_I4;
1115                 ins->opcode += ovfops_op_map [src1->type];
1116                 break;
1117         case CEE_CONV_I:
1118         case CEE_CONV_OVF_I:
1119         case CEE_CONV_OVF_U:
1120                 ins->type = STACK_PTR;
1121                 ins->opcode += ovfops_op_map [src1->type];
1122                 break;
1123         case CEE_ADD_OVF:
1124         case CEE_ADD_OVF_UN:
1125         case CEE_MUL_OVF:
1126         case CEE_MUL_OVF_UN:
1127         case CEE_SUB_OVF:
1128         case CEE_SUB_OVF_UN:
1129                 ins->type = bin_num_table [src1->type] [src2->type];
1130                 ins->opcode += ovfops_op_map [src1->type];
1131                 if (ins->type == STACK_R8)
1132                         ins->type = STACK_INV;
1133                 break;
1134         case OP_LOAD_MEMBASE:
1135                 ins->type = STACK_PTR;
1136                 break;
1137         case OP_LOADI1_MEMBASE:
1138         case OP_LOADU1_MEMBASE:
1139         case OP_LOADI2_MEMBASE:
1140         case OP_LOADU2_MEMBASE:
1141         case OP_LOADI4_MEMBASE:
1142         case OP_LOADU4_MEMBASE:
1143                 ins->type = STACK_PTR;
1144                 break;
1145         case OP_LOADI8_MEMBASE:
1146                 ins->type = STACK_I8;
1147                 break;
1148         case OP_LOADR4_MEMBASE:
1149                 ins->type = cfg->r4_stack_type;
1150                 break;
1151         case OP_LOADR8_MEMBASE:
1152                 ins->type = STACK_R8;
1153                 break;
1154         default:
1155                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1156                 break;
1157         }
1158
1159         if (ins->type == STACK_MP)
1160                 ins->klass = mono_defaults.object_class;
1161 }
1162
1163 static const char 
1164 ldind_type [] = {
1165         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1166 };
1167
1168 #if 0
1169
1170 static const char
1171 param_table [STACK_MAX] [STACK_MAX] = {
1172         {0},
1173 };
1174
1175 static int
1176 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1177 {
1178         int i;
1179
1180         if (sig->hasthis) {
1181                 switch (args->type) {
1182                 case STACK_I4:
1183                 case STACK_I8:
1184                 case STACK_R8:
1185                 case STACK_VTYPE:
1186                 case STACK_INV:
1187                         return 0;
1188                 }
1189                 args++;
1190         }
1191         for (i = 0; i < sig->param_count; ++i) {
1192                 switch (args [i].type) {
1193                 case STACK_INV:
1194                         return 0;
1195                 case STACK_MP:
1196                         if (!sig->params [i]->byref)
1197                                 return 0;
1198                         continue;
1199                 case STACK_OBJ:
1200                         if (sig->params [i]->byref)
1201                                 return 0;
1202                         switch (sig->params [i]->type) {
1203                         case MONO_TYPE_CLASS:
1204                         case MONO_TYPE_STRING:
1205                         case MONO_TYPE_OBJECT:
1206                         case MONO_TYPE_SZARRAY:
1207                         case MONO_TYPE_ARRAY:
1208                                 break;
1209                         default:
1210                                 return 0;
1211                         }
1212                         continue;
1213                 case STACK_R8:
1214                         if (sig->params [i]->byref)
1215                                 return 0;
1216                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1217                                 return 0;
1218                         continue;
1219                 case STACK_PTR:
1220                 case STACK_I4:
1221                 case STACK_I8:
1222                 case STACK_VTYPE:
1223                         break;
1224                 }
1225                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1226                         return 0;*/
1227         }
1228         return 1;
1229 }
1230 #endif
1231
1232 /*
1233  * When we need a pointer to the current domain many times in a method, we
1234  * call mono_domain_get() once and we store the result in a local variable.
1235  * This function returns the variable that represents the MonoDomain*.
1236  */
1237 inline static MonoInst *
1238 mono_get_domainvar (MonoCompile *cfg)
1239 {
1240         if (!cfg->domainvar)
1241                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1242         return cfg->domainvar;
1243 }
1244
1245 /*
1246  * The got_var contains the address of the Global Offset Table when AOT 
1247  * compiling.
1248  */
1249 MonoInst *
1250 mono_get_got_var (MonoCompile *cfg)
1251 {
1252         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1253                 return NULL;
1254         if (!cfg->got_var) {
1255                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1256         }
1257         return cfg->got_var;
1258 }
1259
1260 static MonoInst *
1261 mono_get_vtable_var (MonoCompile *cfg)
1262 {
1263         g_assert (cfg->gshared);
1264
1265         if (!cfg->rgctx_var) {
1266                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1267                 /* force the var to be stack allocated */
1268                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1269         }
1270
1271         return cfg->rgctx_var;
1272 }
1273
1274 static MonoType*
1275 type_from_stack_type (MonoInst *ins) {
1276         switch (ins->type) {
1277         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1278         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1279         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1280         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1281         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1282         case STACK_MP:
1283                 return &ins->klass->this_arg;
1284         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1285         case STACK_VTYPE: return &ins->klass->byval_arg;
1286         default:
1287                 g_error ("stack type %d to monotype not handled\n", ins->type);
1288         }
1289         return NULL;
1290 }
1291
1292 static G_GNUC_UNUSED int
1293 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1294 {
1295         t = mono_type_get_underlying_type (t);
1296         switch (t->type) {
1297         case MONO_TYPE_I1:
1298         case MONO_TYPE_U1:
1299         case MONO_TYPE_I2:
1300         case MONO_TYPE_U2:
1301         case MONO_TYPE_I4:
1302         case MONO_TYPE_U4:
1303                 return STACK_I4;
1304         case MONO_TYPE_I:
1305         case MONO_TYPE_U:
1306         case MONO_TYPE_PTR:
1307         case MONO_TYPE_FNPTR:
1308                 return STACK_PTR;
1309         case MONO_TYPE_CLASS:
1310         case MONO_TYPE_STRING:
1311         case MONO_TYPE_OBJECT:
1312         case MONO_TYPE_SZARRAY:
1313         case MONO_TYPE_ARRAY:    
1314                 return STACK_OBJ;
1315         case MONO_TYPE_I8:
1316         case MONO_TYPE_U8:
1317                 return STACK_I8;
1318         case MONO_TYPE_R4:
1319                 return cfg->r4_stack_type;
1320         case MONO_TYPE_R8:
1321                 return STACK_R8;
1322         case MONO_TYPE_VALUETYPE:
1323         case MONO_TYPE_TYPEDBYREF:
1324                 return STACK_VTYPE;
1325         case MONO_TYPE_GENERICINST:
1326                 if (mono_type_generic_inst_is_valuetype (t))
1327                         return STACK_VTYPE;
1328                 else
1329                         return STACK_OBJ;
1330                 break;
1331         default:
1332                 g_assert_not_reached ();
1333         }
1334
1335         return -1;
1336 }
1337
1338 static MonoClass*
1339 array_access_to_klass (int opcode)
1340 {
1341         switch (opcode) {
1342         case CEE_LDELEM_U1:
1343                 return mono_defaults.byte_class;
1344         case CEE_LDELEM_U2:
1345                 return mono_defaults.uint16_class;
1346         case CEE_LDELEM_I:
1347         case CEE_STELEM_I:
1348                 return mono_defaults.int_class;
1349         case CEE_LDELEM_I1:
1350         case CEE_STELEM_I1:
1351                 return mono_defaults.sbyte_class;
1352         case CEE_LDELEM_I2:
1353         case CEE_STELEM_I2:
1354                 return mono_defaults.int16_class;
1355         case CEE_LDELEM_I4:
1356         case CEE_STELEM_I4:
1357                 return mono_defaults.int32_class;
1358         case CEE_LDELEM_U4:
1359                 return mono_defaults.uint32_class;
1360         case CEE_LDELEM_I8:
1361         case CEE_STELEM_I8:
1362                 return mono_defaults.int64_class;
1363         case CEE_LDELEM_R4:
1364         case CEE_STELEM_R4:
1365                 return mono_defaults.single_class;
1366         case CEE_LDELEM_R8:
1367         case CEE_STELEM_R8:
1368                 return mono_defaults.double_class;
1369         case CEE_LDELEM_REF:
1370         case CEE_STELEM_REF:
1371                 return mono_defaults.object_class;
1372         default:
1373                 g_assert_not_reached ();
1374         }
1375         return NULL;
1376 }
1377
1378 /*
1379  * We try to share variables when possible
1380  */
1381 static MonoInst *
1382 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1383 {
1384         MonoInst *res;
1385         int pos, vnum;
1386
1387         /* inlining can result in deeper stacks */ 
1388         if (slot >= cfg->header->max_stack)
1389                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1390
1391         pos = ins->type - 1 + slot * STACK_MAX;
1392
1393         switch (ins->type) {
1394         case STACK_I4:
1395         case STACK_I8:
1396         case STACK_R8:
1397         case STACK_PTR:
1398         case STACK_MP:
1399         case STACK_OBJ:
1400                 if ((vnum = cfg->intvars [pos]))
1401                         return cfg->varinfo [vnum];
1402                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1403                 cfg->intvars [pos] = res->inst_c0;
1404                 break;
1405         default:
1406                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1407         }
1408         return res;
1409 }
1410
1411 static void
1412 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1413 {
1414         /* 
1415          * Don't use this if a generic_context is set, since that means AOT can't
1416          * look up the method using just the image+token.
1417          * table == 0 means this is a reference made from a wrapper.
1418          */
1419         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1420                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1421                 jump_info_token->image = image;
1422                 jump_info_token->token = token;
1423                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1424         }
1425 }
1426
1427 /*
1428  * This function is called to handle items that are left on the evaluation stack
1429  * at basic block boundaries. What happens is that we save the values to local variables
1430  * and we reload them later when first entering the target basic block (with the
1431  * handle_loaded_temps () function).
1432  * A single joint point will use the same variables (stored in the array bb->out_stack or
1433  * bb->in_stack, if the basic block is before or after the joint point).
1434  *
1435  * This function needs to be called _before_ emitting the last instruction of
1436  * the bb (i.e. before emitting a branch).
1437  * If the stack merge fails at a join point, cfg->unverifiable is set.
1438  */
1439 static void
1440 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1441 {
1442         int i, bindex;
1443         MonoBasicBlock *bb = cfg->cbb;
1444         MonoBasicBlock *outb;
1445         MonoInst *inst, **locals;
1446         gboolean found;
1447
1448         if (!count)
1449                 return;
1450         if (cfg->verbose_level > 3)
1451                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1452         if (!bb->out_scount) {
1453                 bb->out_scount = count;
1454                 //printf ("bblock %d has out:", bb->block_num);
1455                 found = FALSE;
1456                 for (i = 0; i < bb->out_count; ++i) {
1457                         outb = bb->out_bb [i];
1458                         /* exception handlers are linked, but they should not be considered for stack args */
1459                         if (outb->flags & BB_EXCEPTION_HANDLER)
1460                                 continue;
1461                         //printf (" %d", outb->block_num);
1462                         if (outb->in_stack) {
1463                                 found = TRUE;
1464                                 bb->out_stack = outb->in_stack;
1465                                 break;
1466                         }
1467                 }
1468                 //printf ("\n");
1469                 if (!found) {
1470                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1471                         for (i = 0; i < count; ++i) {
1472                                 /* 
1473                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1474                                  * stack slot and if they are of the same type.
1475                                  * This won't cause conflicts since if 'local' is used to 
1476                                  * store one of the values in the in_stack of a bblock, then
1477                                  * the same variable will be used for the same outgoing stack 
1478                                  * slot as well. 
1479                                  * This doesn't work when inlining methods, since the bblocks
1480                                  * in the inlined methods do not inherit their in_stack from
1481                                  * the bblock they are inlined to. See bug #58863 for an
1482                                  * example.
1483                                  */
1484                                 if (cfg->inlined_method)
1485                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1486                                 else
1487                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1488                         }
1489                 }
1490         }
1491
1492         for (i = 0; i < bb->out_count; ++i) {
1493                 outb = bb->out_bb [i];
1494                 /* exception handlers are linked, but they should not be considered for stack args */
1495                 if (outb->flags & BB_EXCEPTION_HANDLER)
1496                         continue;
1497                 if (outb->in_scount) {
1498                         if (outb->in_scount != bb->out_scount) {
1499                                 cfg->unverifiable = TRUE;
1500                                 return;
1501                         }
1502                         continue; /* check they are the same locals */
1503                 }
1504                 outb->in_scount = count;
1505                 outb->in_stack = bb->out_stack;
1506         }
1507
1508         locals = bb->out_stack;
1509         cfg->cbb = bb;
1510         for (i = 0; i < count; ++i) {
1511                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1512                 inst->cil_code = sp [i]->cil_code;
1513                 sp [i] = locals [i];
1514                 if (cfg->verbose_level > 3)
1515                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1516         }
1517
1518         /*
1519          * It is possible that the out bblocks already have in_stack assigned, and
1520          * the in_stacks differ. In this case, we will store to all the different 
1521          * in_stacks.
1522          */
1523
1524         found = TRUE;
1525         bindex = 0;
1526         while (found) {
1527                 /* Find a bblock which has a different in_stack */
1528                 found = FALSE;
1529                 while (bindex < bb->out_count) {
1530                         outb = bb->out_bb [bindex];
1531                         /* exception handlers are linked, but they should not be considered for stack args */
1532                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1533                                 bindex++;
1534                                 continue;
1535                         }
1536                         if (outb->in_stack != locals) {
1537                                 for (i = 0; i < count; ++i) {
1538                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1539                                         inst->cil_code = sp [i]->cil_code;
1540                                         sp [i] = locals [i];
1541                                         if (cfg->verbose_level > 3)
1542                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1543                                 }
1544                                 locals = outb->in_stack;
1545                                 found = TRUE;
1546                                 break;
1547                         }
1548                         bindex ++;
1549                 }
1550         }
1551 }
1552
1553 static MonoInst*
1554 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1555 {
1556         MonoInst *ins;
1557
1558         if (cfg->compile_aot) {
1559                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1560         } else {
1561                 MonoJumpInfo ji;
1562                 gpointer target;
1563                 MonoError error;
1564
1565                 ji.type = patch_type;
1566                 ji.data.target = data;
1567                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1568                 mono_error_assert_ok (&error);
1569
1570                 EMIT_NEW_PCONST (cfg, ins, target);
1571         }
1572         return ins;
1573 }
1574
1575 static void
1576 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1577 {
1578         int ibitmap_reg = alloc_preg (cfg);
1579 #ifdef COMPRESSED_INTERFACE_BITMAP
1580         MonoInst *args [2];
1581         MonoInst *res, *ins;
1582         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1583         MONO_ADD_INS (cfg->cbb, ins);
1584         args [0] = ins;
1585         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1586         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1587         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1588 #else
1589         int ibitmap_byte_reg = alloc_preg (cfg);
1590
1591         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1592
1593         if (cfg->compile_aot) {
1594                 int iid_reg = alloc_preg (cfg);
1595                 int shifted_iid_reg = alloc_preg (cfg);
1596                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1597                 int masked_iid_reg = alloc_preg (cfg);
1598                 int iid_one_bit_reg = alloc_preg (cfg);
1599                 int iid_bit_reg = alloc_preg (cfg);
1600                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1601                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1602                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1603                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1604                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1605                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1606                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1607                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1608         } else {
1609                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1610                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1611         }
1612 #endif
1613 }
1614
1615 /* 
1616  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1617  * stored in "klass_reg" implements the interface "klass".
1618  */
1619 static void
1620 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1621 {
1622         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1623 }
1624
1625 /* 
1626  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1627  * stored in "vtable_reg" implements the interface "klass".
1628  */
1629 static void
1630 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1631 {
1632         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1633 }
1634
1635 /* 
1636  * Emit code which checks whenever the interface id of @klass is smaller than
1637  * than the value given by max_iid_reg.
1638 */
1639 static void
1640 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1641                                                  MonoBasicBlock *false_target)
1642 {
1643         if (cfg->compile_aot) {
1644                 int iid_reg = alloc_preg (cfg);
1645                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1646                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1647         }
1648         else
1649                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1650         if (false_target)
1651                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1652         else
1653                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1654 }
1655
1656 /* Same as above, but obtains max_iid from a vtable */
1657 static void
1658 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1659                                                                  MonoBasicBlock *false_target)
1660 {
1661         int max_iid_reg = alloc_preg (cfg);
1662                 
1663         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1664         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1665 }
1666
1667 /* Same as above, but obtains max_iid from a klass */
1668 static void
1669 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1670                                                                  MonoBasicBlock *false_target)
1671 {
1672         int max_iid_reg = alloc_preg (cfg);
1673
1674         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1675         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1676 }
1677
1678 static void
1679 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1680 {
1681         int idepth_reg = alloc_preg (cfg);
1682         int stypes_reg = alloc_preg (cfg);
1683         int stype = alloc_preg (cfg);
1684
1685         mono_class_setup_supertypes (klass);
1686
1687         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1688                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1689                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1690                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1691         }
1692         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1693         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1694         if (klass_ins) {
1695                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1696         } else if (cfg->compile_aot) {
1697                 int const_reg = alloc_preg (cfg);
1698                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1699                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1700         } else {
1701                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1702         }
1703         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1704 }
1705
1706 static void
1707 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1708 {
1709         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1710 }
1711
1712 static void
1713 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1714 {
1715         int intf_reg = alloc_preg (cfg);
1716
1717         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1718         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1719         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1720         if (true_target)
1721                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1722         else
1723                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1724 }
1725
1726 /*
1727  * Variant of the above that takes a register to the class, not the vtable.
1728  */
1729 static void
1730 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1731 {
1732         int intf_bit_reg = alloc_preg (cfg);
1733
1734         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1735         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1736         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1737         if (true_target)
1738                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1739         else
1740                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1741 }
1742
1743 static inline void
1744 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1745 {
1746         if (klass_inst) {
1747                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1748         } else {
1749                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1750                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1751         }
1752         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1753 }
1754
1755 static inline void
1756 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1757 {
1758         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1759 }
1760
1761 static inline void
1762 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1763 {
1764         if (cfg->compile_aot) {
1765                 int const_reg = alloc_preg (cfg);
1766                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1767                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1768         } else {
1769                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1770         }
1771         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1772 }
1773
1774 static void
1775 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1776         
1777 static void
1778 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1779 {
1780         if (klass->rank) {
1781                 int rank_reg = alloc_preg (cfg);
1782                 int eclass_reg = alloc_preg (cfg);
1783
1784                 g_assert (!klass_inst);
1785                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1786                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1787                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1788                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1789                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1790                 if (klass->cast_class == mono_defaults.object_class) {
1791                         int parent_reg = alloc_preg (cfg);
1792                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1793                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1794                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1795                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1796                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1797                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1798                 } else if (klass->cast_class == mono_defaults.enum_class) {
1799                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1800                 } else if (mono_class_is_interface (klass->cast_class)) {
1801                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1802                 } else {
1803                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1804                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1805                 }
1806
1807                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1808                         /* Check that the object is a vector too */
1809                         int bounds_reg = alloc_preg (cfg);
1810                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1811                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1812                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1813                 }
1814         } else {
1815                 int idepth_reg = alloc_preg (cfg);
1816                 int stypes_reg = alloc_preg (cfg);
1817                 int stype = alloc_preg (cfg);
1818
1819                 mono_class_setup_supertypes (klass);
1820
1821                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1822                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1823                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1824                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1825                 }
1826                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1827                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1828                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1829         }
1830 }
1831
1832 static void
1833 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1834 {
1835         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1836 }
1837
1838 static void 
1839 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1840 {
1841         int val_reg;
1842
1843         g_assert (val == 0);
1844
1845         if (align == 0)
1846                 align = 4;
1847
1848         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1849                 switch (size) {
1850                 case 1:
1851                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1852                         return;
1853                 case 2:
1854                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1855                         return;
1856                 case 4:
1857                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1858                         return;
1859 #if SIZEOF_REGISTER == 8
1860                 case 8:
1861                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1862                         return;
1863 #endif
1864                 }
1865         }
1866
1867         val_reg = alloc_preg (cfg);
1868
1869         if (SIZEOF_REGISTER == 8)
1870                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1871         else
1872                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1873
1874         if (align < 4) {
1875                 /* This could be optimized further if neccesary */
1876                 while (size >= 1) {
1877                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1878                         offset += 1;
1879                         size -= 1;
1880                 }
1881                 return;
1882         }       
1883
1884         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1885                 if (offset % 8) {
1886                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1887                         offset += 4;
1888                         size -= 4;
1889                 }
1890                 while (size >= 8) {
1891                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1892                         offset += 8;
1893                         size -= 8;
1894                 }
1895         }       
1896
1897         while (size >= 4) {
1898                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1899                 offset += 4;
1900                 size -= 4;
1901         }
1902         while (size >= 2) {
1903                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1904                 offset += 2;
1905                 size -= 2;
1906         }
1907         while (size >= 1) {
1908                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1909                 offset += 1;
1910                 size -= 1;
1911         }
1912 }
1913
1914 void 
1915 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1916 {
1917         int cur_reg;
1918
1919         if (align == 0)
1920                 align = 4;
1921
1922         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1923         g_assert (size < 10000);
1924
1925         if (align < 4) {
1926                 /* This could be optimized further if neccesary */
1927                 while (size >= 1) {
1928                         cur_reg = alloc_preg (cfg);
1929                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1930                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1931                         doffset += 1;
1932                         soffset += 1;
1933                         size -= 1;
1934                 }
1935         }
1936
1937         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1938                 while (size >= 8) {
1939                         cur_reg = alloc_preg (cfg);
1940                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1941                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1942                         doffset += 8;
1943                         soffset += 8;
1944                         size -= 8;
1945                 }
1946         }       
1947
1948         while (size >= 4) {
1949                 cur_reg = alloc_preg (cfg);
1950                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1951                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1952                 doffset += 4;
1953                 soffset += 4;
1954                 size -= 4;
1955         }
1956         while (size >= 2) {
1957                 cur_reg = alloc_preg (cfg);
1958                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1959                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1960                 doffset += 2;
1961                 soffset += 2;
1962                 size -= 2;
1963         }
1964         while (size >= 1) {
1965                 cur_reg = alloc_preg (cfg);
1966                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1967                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1968                 doffset += 1;
1969                 soffset += 1;
1970                 size -= 1;
1971         }
1972 }
1973
1974 static void
1975 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1976 {
1977         MonoInst *ins, *c;
1978
1979         if (cfg->compile_aot) {
1980                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1981                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1982                 ins->sreg1 = sreg1;
1983                 ins->sreg2 = c->dreg;
1984                 MONO_ADD_INS (cfg->cbb, ins);
1985         } else {
1986                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1987                 ins->sreg1 = sreg1;
1988                 ins->inst_offset = mini_get_tls_offset (tls_key);
1989                 MONO_ADD_INS (cfg->cbb, ins);
1990         }
1991 }
1992
1993 /*
1994  * emit_push_lmf:
1995  *
1996  *   Emit IR to push the current LMF onto the LMF stack.
1997  */
1998 static void
1999 emit_push_lmf (MonoCompile *cfg)
2000 {
2001         /*
2002          * Emit IR to push the LMF:
2003          * lmf_addr = <lmf_addr from tls>
2004          * lmf->lmf_addr = lmf_addr
2005          * lmf->prev_lmf = *lmf_addr
2006          * *lmf_addr = lmf
2007          */
2008         int lmf_reg, prev_lmf_reg;
2009         MonoInst *ins, *lmf_ins;
2010
2011         if (!cfg->lmf_ir)
2012                 return;
2013
2014         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2015                 /* Load current lmf */
2016                 lmf_ins = mono_get_lmf_intrinsic (cfg);
2017                 g_assert (lmf_ins);
2018                 MONO_ADD_INS (cfg->cbb, lmf_ins);
2019                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2020                 lmf_reg = ins->dreg;
2021                 /* Save previous_lmf */
2022                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2023                 /* Set new LMF */
2024                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2025         } else {
2026                 /*
2027                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2028                  */
2029                 if (!cfg->lmf_addr_var)
2030                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2031
2032 #ifdef HOST_WIN32
2033                 ins = mono_get_jit_tls_intrinsic (cfg);
2034                 if (ins) {
2035                         int jit_tls_dreg = ins->dreg;
2036
2037                         MONO_ADD_INS (cfg->cbb, ins);
2038                         lmf_reg = alloc_preg (cfg);
2039                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2040                 } else {
2041                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2042                 }
2043 #else
2044                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2045                 if (lmf_ins) {
2046                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2047                 } else {
2048 #ifdef TARGET_IOS
2049                         MonoInst *args [16], *jit_tls_ins, *ins;
2050
2051                         /* Inline mono_get_lmf_addr () */
2052                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2053
2054                         /* Load mono_jit_tls_id */
2055                         if (cfg->compile_aot)
2056                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2057                         else
2058                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2059                         /* call pthread_getspecific () */
2060                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2061                         /* lmf_addr = &jit_tls->lmf */
2062                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2063                         lmf_ins = ins;
2064 #else
2065                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2066 #endif
2067                 }
2068 #endif
2069                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2070
2071                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2072                 lmf_reg = ins->dreg;
2073
2074                 prev_lmf_reg = alloc_preg (cfg);
2075                 /* Save previous_lmf */
2076                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2077                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2078                 /* Set new lmf */
2079                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2080         }
2081 }
2082
2083 /*
2084  * emit_pop_lmf:
2085  *
2086  *   Emit IR to pop the current LMF from the LMF stack.
2087  */
2088 static void
2089 emit_pop_lmf (MonoCompile *cfg)
2090 {
2091         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2092         MonoInst *ins;
2093
2094         if (!cfg->lmf_ir)
2095                 return;
2096
2097         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2098         lmf_reg = ins->dreg;
2099
2100         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2101                 /* Load previous_lmf */
2102                 prev_lmf_reg = alloc_preg (cfg);
2103                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2104                 /* Set new LMF */
2105                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2106         } else {
2107                 /*
2108                  * Emit IR to pop the LMF:
2109                  * *(lmf->lmf_addr) = lmf->prev_lmf
2110                  */
2111                 /* This could be called before emit_push_lmf () */
2112                 if (!cfg->lmf_addr_var)
2113                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2114                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2115
2116                 prev_lmf_reg = alloc_preg (cfg);
2117                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2118                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2119         }
2120 }
2121
2122 static void
2123 emit_instrumentation_call (MonoCompile *cfg, void *func)
2124 {
2125         MonoInst *iargs [1];
2126
2127         /*
2128          * Avoid instrumenting inlined methods since it can
2129          * distort profiling results.
2130          */
2131         if (cfg->method != cfg->current_method)
2132                 return;
2133
2134         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2135                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2136                 mono_emit_jit_icall (cfg, func, iargs);
2137         }
2138 }
2139
2140 static int
2141 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2142 {
2143 handle_enum:
2144         type = mini_get_underlying_type (type);
2145         switch (type->type) {
2146         case MONO_TYPE_VOID:
2147                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2148         case MONO_TYPE_I1:
2149         case MONO_TYPE_U1:
2150         case MONO_TYPE_I2:
2151         case MONO_TYPE_U2:
2152         case MONO_TYPE_I4:
2153         case MONO_TYPE_U4:
2154                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2155         case MONO_TYPE_I:
2156         case MONO_TYPE_U:
2157         case MONO_TYPE_PTR:
2158         case MONO_TYPE_FNPTR:
2159                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2160         case MONO_TYPE_CLASS:
2161         case MONO_TYPE_STRING:
2162         case MONO_TYPE_OBJECT:
2163         case MONO_TYPE_SZARRAY:
2164         case MONO_TYPE_ARRAY:    
2165                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2166         case MONO_TYPE_I8:
2167         case MONO_TYPE_U8:
2168                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2169         case MONO_TYPE_R4:
2170                 if (cfg->r4fp)
2171                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2172                 else
2173                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2174         case MONO_TYPE_R8:
2175                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2176         case MONO_TYPE_VALUETYPE:
2177                 if (type->data.klass->enumtype) {
2178                         type = mono_class_enum_basetype (type->data.klass);
2179                         goto handle_enum;
2180                 } else
2181                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2182         case MONO_TYPE_TYPEDBYREF:
2183                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2184         case MONO_TYPE_GENERICINST:
2185                 type = &type->data.generic_class->container_class->byval_arg;
2186                 goto handle_enum;
2187         case MONO_TYPE_VAR:
2188         case MONO_TYPE_MVAR:
2189                 /* gsharedvt */
2190                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2191         default:
2192                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2193         }
2194         return -1;
2195 }
2196
2197 //XXX this ignores if t is byref
2198 #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)))))
2199
2200 /*
2201  * target_type_is_incompatible:
2202  * @cfg: MonoCompile context
2203  *
2204  * Check that the item @arg on the evaluation stack can be stored
2205  * in the target type (can be a local, or field, etc).
2206  * The cfg arg can be used to check if we need verification or just
2207  * validity checks.
2208  *
2209  * Returns: non-0 value if arg can't be stored on a target.
2210  */
2211 static int
2212 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2213 {
2214         MonoType *simple_type;
2215         MonoClass *klass;
2216
2217         if (target->byref) {
2218                 /* FIXME: check that the pointed to types match */
2219                 if (arg->type == STACK_MP) {
2220                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
2221                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
2222                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
2223
2224                         /* if the target is native int& or same type */
2225                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
2226                                 return 0;
2227
2228                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
2229                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
2230                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
2231                                 return 0;
2232                         return 1;
2233                 }
2234                 if (arg->type == STACK_PTR)
2235                         return 0;
2236                 return 1;
2237         }
2238
2239         simple_type = mini_get_underlying_type (target);
2240         switch (simple_type->type) {
2241         case MONO_TYPE_VOID:
2242                 return 1;
2243         case MONO_TYPE_I1:
2244         case MONO_TYPE_U1:
2245         case MONO_TYPE_I2:
2246         case MONO_TYPE_U2:
2247         case MONO_TYPE_I4:
2248         case MONO_TYPE_U4:
2249                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2250                         return 1;
2251                 return 0;
2252         case MONO_TYPE_PTR:
2253                 /* STACK_MP is needed when setting pinned locals */
2254                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2255                         return 1;
2256                 return 0;
2257         case MONO_TYPE_I:
2258         case MONO_TYPE_U:
2259         case MONO_TYPE_FNPTR:
2260                 /* 
2261                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2262                  * in native int. (#688008).
2263                  */
2264                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2265                         return 1;
2266                 return 0;
2267         case MONO_TYPE_CLASS:
2268         case MONO_TYPE_STRING:
2269         case MONO_TYPE_OBJECT:
2270         case MONO_TYPE_SZARRAY:
2271         case MONO_TYPE_ARRAY:    
2272                 if (arg->type != STACK_OBJ)
2273                         return 1;
2274                 /* FIXME: check type compatibility */
2275                 return 0;
2276         case MONO_TYPE_I8:
2277         case MONO_TYPE_U8:
2278                 if (arg->type != STACK_I8)
2279                         return 1;
2280                 return 0;
2281         case MONO_TYPE_R4:
2282                 if (arg->type != cfg->r4_stack_type)
2283                         return 1;
2284                 return 0;
2285         case MONO_TYPE_R8:
2286                 if (arg->type != STACK_R8)
2287                         return 1;
2288                 return 0;
2289         case MONO_TYPE_VALUETYPE:
2290                 if (arg->type != STACK_VTYPE)
2291                         return 1;
2292                 klass = mono_class_from_mono_type (simple_type);
2293                 if (klass != arg->klass)
2294                         return 1;
2295                 return 0;
2296         case MONO_TYPE_TYPEDBYREF:
2297                 if (arg->type != STACK_VTYPE)
2298                         return 1;
2299                 klass = mono_class_from_mono_type (simple_type);
2300                 if (klass != arg->klass)
2301                         return 1;
2302                 return 0;
2303         case MONO_TYPE_GENERICINST:
2304                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2305                         MonoClass *target_class;
2306                         if (arg->type != STACK_VTYPE)
2307                                 return 1;
2308                         klass = mono_class_from_mono_type (simple_type);
2309                         target_class = mono_class_from_mono_type (target);
2310                         /* The second cases is needed when doing partial sharing */
2311                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2312                                 return 1;
2313                         return 0;
2314                 } else {
2315                         if (arg->type != STACK_OBJ)
2316                                 return 1;
2317                         /* FIXME: check type compatibility */
2318                         return 0;
2319                 }
2320         case MONO_TYPE_VAR:
2321         case MONO_TYPE_MVAR:
2322                 g_assert (cfg->gshared);
2323                 if (mini_type_var_is_vt (simple_type)) {
2324                         if (arg->type != STACK_VTYPE)
2325                                 return 1;
2326                 } else {
2327                         if (arg->type != STACK_OBJ)
2328                                 return 1;
2329                 }
2330                 return 0;
2331         default:
2332                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2333         }
2334         return 1;
2335 }
2336
2337 /*
2338  * Prepare arguments for passing to a function call.
2339  * Return a non-zero value if the arguments can't be passed to the given
2340  * signature.
2341  * The type checks are not yet complete and some conversions may need
2342  * casts on 32 or 64 bit architectures.
2343  *
2344  * FIXME: implement this using target_type_is_incompatible ()
2345  */
2346 static int
2347 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2348 {
2349         MonoType *simple_type;
2350         int i;
2351
2352         if (sig->hasthis) {
2353                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2354                         return 1;
2355                 args++;
2356         }
2357         for (i = 0; i < sig->param_count; ++i) {
2358                 if (sig->params [i]->byref) {
2359                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2360                                 return 1;
2361                         continue;
2362                 }
2363                 simple_type = mini_get_underlying_type (sig->params [i]);
2364 handle_enum:
2365                 switch (simple_type->type) {
2366                 case MONO_TYPE_VOID:
2367                         return 1;
2368                         continue;
2369                 case MONO_TYPE_I1:
2370                 case MONO_TYPE_U1:
2371                 case MONO_TYPE_I2:
2372                 case MONO_TYPE_U2:
2373                 case MONO_TYPE_I4:
2374                 case MONO_TYPE_U4:
2375                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2376                                 return 1;
2377                         continue;
2378                 case MONO_TYPE_I:
2379                 case MONO_TYPE_U:
2380                 case MONO_TYPE_PTR:
2381                 case MONO_TYPE_FNPTR:
2382                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2383                                 return 1;
2384                         continue;
2385                 case MONO_TYPE_CLASS:
2386                 case MONO_TYPE_STRING:
2387                 case MONO_TYPE_OBJECT:
2388                 case MONO_TYPE_SZARRAY:
2389                 case MONO_TYPE_ARRAY:    
2390                         if (args [i]->type != STACK_OBJ)
2391                                 return 1;
2392                         continue;
2393                 case MONO_TYPE_I8:
2394                 case MONO_TYPE_U8:
2395                         if (args [i]->type != STACK_I8)
2396                                 return 1;
2397                         continue;
2398                 case MONO_TYPE_R4:
2399                         if (args [i]->type != cfg->r4_stack_type)
2400                                 return 1;
2401                         continue;
2402                 case MONO_TYPE_R8:
2403                         if (args [i]->type != STACK_R8)
2404                                 return 1;
2405                         continue;
2406                 case MONO_TYPE_VALUETYPE:
2407                         if (simple_type->data.klass->enumtype) {
2408                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2409                                 goto handle_enum;
2410                         }
2411                         if (args [i]->type != STACK_VTYPE)
2412                                 return 1;
2413                         continue;
2414                 case MONO_TYPE_TYPEDBYREF:
2415                         if (args [i]->type != STACK_VTYPE)
2416                                 return 1;
2417                         continue;
2418                 case MONO_TYPE_GENERICINST:
2419                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2420                         goto handle_enum;
2421                 case MONO_TYPE_VAR:
2422                 case MONO_TYPE_MVAR:
2423                         /* gsharedvt */
2424                         if (args [i]->type != STACK_VTYPE)
2425                                 return 1;
2426                         continue;
2427                 default:
2428                         g_error ("unknown type 0x%02x in check_call_signature",
2429                                  simple_type->type);
2430                 }
2431         }
2432         return 0;
2433 }
2434
2435 static int
2436 callvirt_to_call (int opcode)
2437 {
2438         switch (opcode) {
2439         case OP_CALL_MEMBASE:
2440                 return OP_CALL;
2441         case OP_VOIDCALL_MEMBASE:
2442                 return OP_VOIDCALL;
2443         case OP_FCALL_MEMBASE:
2444                 return OP_FCALL;
2445         case OP_RCALL_MEMBASE:
2446                 return OP_RCALL;
2447         case OP_VCALL_MEMBASE:
2448                 return OP_VCALL;
2449         case OP_LCALL_MEMBASE:
2450                 return OP_LCALL;
2451         default:
2452                 g_assert_not_reached ();
2453         }
2454
2455         return -1;
2456 }
2457
2458 static int
2459 callvirt_to_call_reg (int opcode)
2460 {
2461         switch (opcode) {
2462         case OP_CALL_MEMBASE:
2463                 return OP_CALL_REG;
2464         case OP_VOIDCALL_MEMBASE:
2465                 return OP_VOIDCALL_REG;
2466         case OP_FCALL_MEMBASE:
2467                 return OP_FCALL_REG;
2468         case OP_RCALL_MEMBASE:
2469                 return OP_RCALL_REG;
2470         case OP_VCALL_MEMBASE:
2471                 return OP_VCALL_REG;
2472         case OP_LCALL_MEMBASE:
2473                 return OP_LCALL_REG;
2474         default:
2475                 g_assert_not_reached ();
2476         }
2477
2478         return -1;
2479 }
2480
2481 /* Either METHOD or IMT_ARG needs to be set */
2482 static void
2483 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2484 {
2485         int method_reg;
2486
2487         if (COMPILE_LLVM (cfg)) {
2488                 if (imt_arg) {
2489                         method_reg = alloc_preg (cfg);
2490                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2491                 } else {
2492                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2493                         method_reg = ins->dreg;
2494                 }
2495
2496 #ifdef ENABLE_LLVM
2497                 call->imt_arg_reg = method_reg;
2498 #endif
2499                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2500                 return;
2501         }
2502
2503         if (imt_arg) {
2504                 method_reg = alloc_preg (cfg);
2505                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2506         } else {
2507                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2508                 method_reg = ins->dreg;
2509         }
2510
2511         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2512 }
2513
2514 static MonoJumpInfo *
2515 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2516 {
2517         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2518
2519         ji->ip.i = ip;
2520         ji->type = type;
2521         ji->data.target = target;
2522
2523         return ji;
2524 }
2525
2526 static int
2527 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2528 {
2529         if (cfg->gshared)
2530                 return mono_class_check_context_used (klass);
2531         else
2532                 return 0;
2533 }
2534
2535 static int
2536 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2537 {
2538         if (cfg->gshared)
2539                 return mono_method_check_context_used (method);
2540         else
2541                 return 0;
2542 }
2543
2544 /*
2545  * check_method_sharing:
2546  *
2547  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2548  */
2549 static void
2550 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2551 {
2552         gboolean pass_vtable = FALSE;
2553         gboolean pass_mrgctx = FALSE;
2554
2555         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2556                 (mono_class_is_ginst (cmethod->klass) || mono_class_is_gtd (cmethod->klass))) {
2557                 gboolean sharable = FALSE;
2558
2559                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2560                         sharable = TRUE;
2561
2562                 /*
2563                  * Pass vtable iff target method might
2564                  * be shared, which means that sharing
2565                  * is enabled for its class and its
2566                  * context is sharable (and it's not a
2567                  * generic method).
2568                  */
2569                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2570                         pass_vtable = TRUE;
2571         }
2572
2573         if (mini_method_get_context (cmethod) &&
2574                 mini_method_get_context (cmethod)->method_inst) {
2575                 g_assert (!pass_vtable);
2576
2577                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2578                         pass_mrgctx = TRUE;
2579                 } else {
2580                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2581                                 pass_mrgctx = TRUE;
2582                 }
2583         }
2584
2585         if (out_pass_vtable)
2586                 *out_pass_vtable = pass_vtable;
2587         if (out_pass_mrgctx)
2588                 *out_pass_mrgctx = pass_mrgctx;
2589 }
2590
2591 inline static MonoCallInst *
2592 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2593                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2594 {
2595         MonoType *sig_ret;
2596         MonoCallInst *call;
2597 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2598         int i;
2599 #endif
2600
2601         if (cfg->llvm_only)
2602                 tail = FALSE;
2603
2604         if (tail) {
2605                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2606
2607                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2608         } else
2609                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2610
2611         call->args = args;
2612         call->signature = sig;
2613         call->rgctx_reg = rgctx;
2614         sig_ret = mini_get_underlying_type (sig->ret);
2615
2616         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2617
2618         if (tail) {
2619                 if (mini_type_is_vtype (sig_ret)) {
2620                         call->vret_var = cfg->vret_addr;
2621                         //g_assert_not_reached ();
2622                 }
2623         } else if (mini_type_is_vtype (sig_ret)) {
2624                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2625                 MonoInst *loada;
2626
2627                 temp->backend.is_pinvoke = sig->pinvoke;
2628
2629                 /*
2630                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2631                  * address of return value to increase optimization opportunities.
2632                  * Before vtype decomposition, the dreg of the call ins itself represents the
2633                  * fact the call modifies the return value. After decomposition, the call will
2634                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2635                  * will be transformed into an LDADDR.
2636                  */
2637                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2638                 loada->dreg = alloc_preg (cfg);
2639                 loada->inst_p0 = temp;
2640                 /* We reference the call too since call->dreg could change during optimization */
2641                 loada->inst_p1 = call;
2642                 MONO_ADD_INS (cfg->cbb, loada);
2643
2644                 call->inst.dreg = temp->dreg;
2645
2646                 call->vret_var = loada;
2647         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2648                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2649
2650 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2651         if (COMPILE_SOFT_FLOAT (cfg)) {
2652                 /* 
2653                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2654                  * an icall, but that cannot be done during the call sequence since it would clobber
2655                  * the call registers + the stack. So we do it before emitting the call.
2656                  */
2657                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2658                         MonoType *t;
2659                         MonoInst *in = call->args [i];
2660
2661                         if (i >= sig->hasthis)
2662                                 t = sig->params [i - sig->hasthis];
2663                         else
2664                                 t = &mono_defaults.int_class->byval_arg;
2665                         t = mono_type_get_underlying_type (t);
2666
2667                         if (!t->byref && t->type == MONO_TYPE_R4) {
2668                                 MonoInst *iargs [1];
2669                                 MonoInst *conv;
2670
2671                                 iargs [0] = in;
2672                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2673
2674                                 /* The result will be in an int vreg */
2675                                 call->args [i] = conv;
2676                         }
2677                 }
2678         }
2679 #endif
2680
2681         call->need_unbox_trampoline = unbox_trampoline;
2682
2683 #ifdef ENABLE_LLVM
2684         if (COMPILE_LLVM (cfg))
2685                 mono_llvm_emit_call (cfg, call);
2686         else
2687                 mono_arch_emit_call (cfg, call);
2688 #else
2689         mono_arch_emit_call (cfg, call);
2690 #endif
2691
2692         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2693         cfg->flags |= MONO_CFG_HAS_CALLS;
2694         
2695         return call;
2696 }
2697
2698 static void
2699 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2700 {
2701         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2702         cfg->uses_rgctx_reg = TRUE;
2703         call->rgctx_reg = TRUE;
2704 #ifdef ENABLE_LLVM
2705         call->rgctx_arg_reg = rgctx_reg;
2706 #endif
2707 }       
2708
2709 inline static MonoInst*
2710 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2711 {
2712         MonoCallInst *call;
2713         MonoInst *ins;
2714         int rgctx_reg = -1;
2715         gboolean check_sp = FALSE;
2716
2717         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2718                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2719
2720                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2721                         check_sp = TRUE;
2722         }
2723
2724         if (rgctx_arg) {
2725                 rgctx_reg = mono_alloc_preg (cfg);
2726                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2727         }
2728
2729         if (check_sp) {
2730                 if (!cfg->stack_inbalance_var)
2731                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2732
2733                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2734                 ins->dreg = cfg->stack_inbalance_var->dreg;
2735                 MONO_ADD_INS (cfg->cbb, ins);
2736         }
2737
2738         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2739
2740         call->inst.sreg1 = addr->dreg;
2741
2742         if (imt_arg)
2743                 emit_imt_argument (cfg, call, NULL, imt_arg);
2744
2745         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2746
2747         if (check_sp) {
2748                 int sp_reg;
2749
2750                 sp_reg = mono_alloc_preg (cfg);
2751
2752                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2753                 ins->dreg = sp_reg;
2754                 MONO_ADD_INS (cfg->cbb, ins);
2755
2756                 /* Restore the stack so we don't crash when throwing the exception */
2757                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2758                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2759                 MONO_ADD_INS (cfg->cbb, ins);
2760
2761                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2762                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2763         }
2764
2765         if (rgctx_arg)
2766                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2767
2768         return (MonoInst*)call;
2769 }
2770
2771 static MonoInst*
2772 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2773
2774 static MonoInst*
2775 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2776 static MonoInst*
2777 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2778
2779 static MonoInst*
2780 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2781                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2782 {
2783 #ifndef DISABLE_REMOTING
2784         gboolean might_be_remote = FALSE;
2785 #endif
2786         gboolean virtual_ = this_ins != NULL;
2787         gboolean enable_for_aot = TRUE;
2788         int context_used;
2789         MonoCallInst *call;
2790         MonoInst *call_target = NULL;
2791         int rgctx_reg = 0;
2792         gboolean need_unbox_trampoline;
2793
2794         if (!sig)
2795                 sig = mono_method_signature (method);
2796
2797         if (cfg->llvm_only && (mono_class_is_interface (method->klass)))
2798                 g_assert_not_reached ();
2799
2800         if (rgctx_arg) {
2801                 rgctx_reg = mono_alloc_preg (cfg);
2802                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2803         }
2804
2805         if (method->string_ctor) {
2806                 /* Create the real signature */
2807                 /* FIXME: Cache these */
2808                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2809                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2810
2811                 sig = ctor_sig;
2812         }
2813
2814         context_used = mini_method_check_context_used (cfg, method);
2815
2816 #ifndef DISABLE_REMOTING
2817         might_be_remote = this_ins && sig->hasthis &&
2818                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2819                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2820
2821         if (might_be_remote && context_used) {
2822                 MonoInst *addr;
2823
2824                 g_assert (cfg->gshared);
2825
2826                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2827
2828                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2829         }
2830 #endif
2831
2832         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2833                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2834
2835         need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass);
2836
2837         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2838
2839 #ifndef DISABLE_REMOTING
2840         if (might_be_remote)
2841                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2842         else
2843 #endif
2844                 call->method = method;
2845         call->inst.flags |= MONO_INST_HAS_METHOD;
2846         call->inst.inst_left = this_ins;
2847         call->tail_call = tail;
2848
2849         if (virtual_) {
2850                 int vtable_reg, slot_reg, this_reg;
2851                 int offset;
2852
2853                 this_reg = this_ins->dreg;
2854
2855                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2856                         MonoInst *dummy_use;
2857
2858                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2859
2860                         /* Make a call to delegate->invoke_impl */
2861                         call->inst.inst_basereg = this_reg;
2862                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2863                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2864
2865                         /* We must emit a dummy use here because the delegate trampoline will
2866                         replace the 'this' argument with the delegate target making this activation
2867                         no longer a root for the delegate.
2868                         This is an issue for delegates that target collectible code such as dynamic
2869                         methods of GC'able assemblies.
2870
2871                         For a test case look into #667921.
2872
2873                         FIXME: a dummy use is not the best way to do it as the local register allocator
2874                         will put it on a caller save register and spil it around the call. 
2875                         Ideally, we would either put it on a callee save register or only do the store part.  
2876                          */
2877                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2878
2879                         return (MonoInst*)call;
2880                 }
2881
2882                 if ((!cfg->compile_aot || enable_for_aot) && 
2883                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2884                          (MONO_METHOD_IS_FINAL (method) &&
2885                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2886                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2887                         /* 
2888                          * the method is not virtual, we just need to ensure this is not null
2889                          * and then we can call the method directly.
2890                          */
2891 #ifndef DISABLE_REMOTING
2892                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2893                                 /* 
2894                                  * The check above ensures method is not gshared, this is needed since
2895                                  * gshared methods can't have wrappers.
2896                                  */
2897                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2898                         }
2899 #endif
2900
2901                         if (!method->string_ctor)
2902                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2903
2904                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2905                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2906                         /*
2907                          * the method is virtual, but we can statically dispatch since either
2908                          * it's class or the method itself are sealed.
2909                          * But first we need to ensure it's not a null reference.
2910                          */
2911                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2912
2913                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2914                 } else if (call_target) {
2915                         vtable_reg = alloc_preg (cfg);
2916                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2917
2918                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2919                         call->inst.sreg1 = call_target->dreg;
2920                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2921                 } else {
2922                         vtable_reg = alloc_preg (cfg);
2923                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2924                         if (mono_class_is_interface (method->klass)) {
2925                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2926                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2927                                 slot_reg = vtable_reg;
2928                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2929                         } else {
2930                                 slot_reg = vtable_reg;
2931                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2932                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2933                                 if (imt_arg) {
2934                                         g_assert (mono_method_signature (method)->generic_param_count);
2935                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2936                                 }
2937                         }
2938
2939                         call->inst.sreg1 = slot_reg;
2940                         call->inst.inst_offset = offset;
2941                         call->is_virtual = TRUE;
2942                 }
2943         }
2944
2945         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2946
2947         if (rgctx_arg)
2948                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2949
2950         return (MonoInst*)call;
2951 }
2952
2953 MonoInst*
2954 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2955 {
2956         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2957 }
2958
2959 MonoInst*
2960 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2961                                            MonoInst **args)
2962 {
2963         MonoCallInst *call;
2964
2965         g_assert (sig);
2966
2967         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2968         call->fptr = func;
2969
2970         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2971
2972         return (MonoInst*)call;
2973 }
2974
2975 MonoInst*
2976 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2977 {
2978         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2979
2980         g_assert (info);
2981
2982         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2983 }
2984
2985 /*
2986  * mono_emit_abs_call:
2987  *
2988  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2989  */
2990 inline static MonoInst*
2991 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2992                                         MonoMethodSignature *sig, MonoInst **args)
2993 {
2994         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2995         MonoInst *ins;
2996
2997         /* 
2998          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2999          * handle it.
3000          */
3001         if (cfg->abs_patches == NULL)
3002                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
3003         g_hash_table_insert (cfg->abs_patches, ji, ji);
3004         ins = mono_emit_native_call (cfg, ji, sig, args);
3005         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
3006         return ins;
3007 }
3008
3009 static MonoMethodSignature*
3010 sig_to_rgctx_sig (MonoMethodSignature *sig)
3011 {
3012         // FIXME: memory allocation
3013         MonoMethodSignature *res;
3014         int i;
3015
3016         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
3017         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
3018         res->param_count = sig->param_count + 1;
3019         for (i = 0; i < sig->param_count; ++i)
3020                 res->params [i] = sig->params [i];
3021         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
3022         return res;
3023 }
3024
3025 /* Make an indirect call to FSIG passing an additional argument */
3026 static MonoInst*
3027 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
3028 {
3029         MonoMethodSignature *csig;
3030         MonoInst *args_buf [16];
3031         MonoInst **args;
3032         int i, pindex, tmp_reg;
3033
3034         /* Make a call with an rgctx/extra arg */
3035         if (fsig->param_count + 2 < 16)
3036                 args = args_buf;
3037         else
3038                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
3039         pindex = 0;
3040         if (fsig->hasthis)
3041                 args [pindex ++] = orig_args [0];
3042         for (i = 0; i < fsig->param_count; ++i)
3043                 args [pindex ++] = orig_args [fsig->hasthis + i];
3044         tmp_reg = alloc_preg (cfg);
3045         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
3046         csig = sig_to_rgctx_sig (fsig);
3047         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
3048 }
3049
3050 /* Emit an indirect call to the function descriptor ADDR */
3051 static MonoInst*
3052 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
3053 {
3054         int addr_reg, arg_reg;
3055         MonoInst *call_target;
3056
3057         g_assert (cfg->llvm_only);
3058
3059         /*
3060          * addr points to a <addr, arg> pair, load both of them, and
3061          * make a call to addr, passing arg as an extra arg.
3062          */
3063         addr_reg = alloc_preg (cfg);
3064         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
3065         arg_reg = alloc_preg (cfg);
3066         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
3067
3068         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
3069 }
3070
3071 static gboolean
3072 direct_icalls_enabled (MonoCompile *cfg)
3073 {
3074         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3075 #ifdef TARGET_AMD64
3076         if (cfg->compile_llvm && !cfg->llvm_only)
3077                 return FALSE;
3078 #endif
3079         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3080                 return FALSE;
3081         return TRUE;
3082 }
3083
3084 MonoInst*
3085 mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
3086 {
3087         /*
3088          * Call the jit icall without a wrapper if possible.
3089          * The wrapper is needed for the following reasons:
3090          * - to handle exceptions thrown using mono_raise_exceptions () from the
3091          *   icall function. The EH code needs the lmf frame pushed by the
3092          *   wrapper to be able to unwind back to managed code.
3093          * - to be able to do stack walks for asynchronously suspended
3094          *   threads when debugging.
3095          */
3096         if (info->no_raise && direct_icalls_enabled (cfg)) {
3097                 char *name;
3098                 int costs;
3099
3100                 if (!info->wrapper_method) {
3101                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3102                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3103                         g_free (name);
3104                         mono_memory_barrier ();
3105                 }
3106
3107                 /*
3108                  * Inline the wrapper method, which is basically a call to the C icall, and
3109                  * an exception check.
3110                  */
3111                 costs = inline_method (cfg, info->wrapper_method, NULL,
3112                                                            args, NULL, il_offset, TRUE);
3113                 g_assert (costs > 0);
3114                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3115
3116                 return args [0];
3117         } else {
3118                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3119         }
3120 }
3121  
3122 static MonoInst*
3123 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3124 {
3125         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3126                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3127                         int widen_op = -1;
3128
3129                         /* 
3130                          * Native code might return non register sized integers 
3131                          * without initializing the upper bits.
3132                          */
3133                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3134                         case OP_LOADI1_MEMBASE:
3135                                 widen_op = OP_ICONV_TO_I1;
3136                                 break;
3137                         case OP_LOADU1_MEMBASE:
3138                                 widen_op = OP_ICONV_TO_U1;
3139                                 break;
3140                         case OP_LOADI2_MEMBASE:
3141                                 widen_op = OP_ICONV_TO_I2;
3142                                 break;
3143                         case OP_LOADU2_MEMBASE:
3144                                 widen_op = OP_ICONV_TO_U2;
3145                                 break;
3146                         default:
3147                                 break;
3148                         }
3149
3150                         if (widen_op != -1) {
3151                                 int dreg = alloc_preg (cfg);
3152                                 MonoInst *widen;
3153
3154                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3155                                 widen->type = ins->type;
3156                                 ins = widen;
3157                         }
3158                 }
3159         }
3160
3161         return ins;
3162 }
3163
3164
3165 static void
3166 emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
3167 {
3168         MonoInst *args [16];
3169
3170         args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
3171         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
3172
3173         mono_emit_jit_icall (cfg, mono_throw_method_access, args);
3174 }
3175
3176 static MonoMethod*
3177 get_memcpy_method (void)
3178 {
3179         static MonoMethod *memcpy_method = NULL;
3180         if (!memcpy_method) {
3181                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3182                 if (!memcpy_method)
3183                         g_error ("Old corlib found. Install a new one");
3184         }
3185         return memcpy_method;
3186 }
3187
3188 static void
3189 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3190 {
3191         MonoClassField *field;
3192         gpointer iter = NULL;
3193
3194         while ((field = mono_class_get_fields (klass, &iter))) {
3195                 int foffset;
3196
3197                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3198                         continue;
3199                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3200                 if (mini_type_is_reference (mono_field_get_type (field))) {
3201                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3202                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3203                 } else {
3204                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3205                         if (field_class->has_references)
3206                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3207                 }
3208         }
3209 }
3210
3211 static void
3212 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3213 {
3214         int card_table_shift_bits;
3215         gpointer card_table_mask;
3216         guint8 *card_table;
3217         MonoInst *dummy_use;
3218         int nursery_shift_bits;
3219         size_t nursery_size;
3220
3221         if (!cfg->gen_write_barriers)
3222                 return;
3223
3224         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3225
3226         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3227
3228         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3229                 MonoInst *wbarrier;
3230
3231                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3232                 wbarrier->sreg1 = ptr->dreg;
3233                 wbarrier->sreg2 = value->dreg;
3234                 MONO_ADD_INS (cfg->cbb, wbarrier);
3235         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3236                 int offset_reg = alloc_preg (cfg);
3237                 int card_reg;
3238                 MonoInst *ins;
3239
3240                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3241                 if (card_table_mask)
3242                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3243
3244                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3245                  * IMM's larger than 32bits.
3246                  */
3247                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3248                 card_reg = ins->dreg;
3249
3250                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3251                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3252         } else {
3253                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3254                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3255         }
3256
3257         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3258 }
3259
3260 static gboolean
3261 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3262 {
3263         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3264         unsigned need_wb = 0;
3265
3266         if (align == 0)
3267                 align = 4;
3268
3269         /*types with references can't have alignment smaller than sizeof(void*) */
3270         if (align < SIZEOF_VOID_P)
3271                 return FALSE;
3272
3273         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3274         if (size > 32 * SIZEOF_VOID_P)
3275                 return FALSE;
3276
3277         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3278
3279         /* We don't unroll more than 5 stores to avoid code bloat. */
3280         if (size > 5 * SIZEOF_VOID_P) {
3281                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3282                 size += (SIZEOF_VOID_P - 1);
3283                 size &= ~(SIZEOF_VOID_P - 1);
3284
3285                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3286                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3287                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3288                 return TRUE;
3289         }
3290
3291         destreg = iargs [0]->dreg;
3292         srcreg = iargs [1]->dreg;
3293         offset = 0;
3294
3295         dest_ptr_reg = alloc_preg (cfg);
3296         tmp_reg = alloc_preg (cfg);
3297
3298         /*tmp = dreg*/
3299         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3300
3301         while (size >= SIZEOF_VOID_P) {
3302                 MonoInst *load_inst;
3303                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3304                 load_inst->dreg = tmp_reg;
3305                 load_inst->inst_basereg = srcreg;
3306                 load_inst->inst_offset = offset;
3307                 MONO_ADD_INS (cfg->cbb, load_inst);
3308
3309                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3310
3311                 if (need_wb & 0x1)
3312                         emit_write_barrier (cfg, iargs [0], load_inst);
3313
3314                 offset += SIZEOF_VOID_P;
3315                 size -= SIZEOF_VOID_P;
3316                 need_wb >>= 1;
3317
3318                 /*tmp += sizeof (void*)*/
3319                 if (size >= SIZEOF_VOID_P) {
3320                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3321                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3322                 }
3323         }
3324
3325         /* Those cannot be references since size < sizeof (void*) */
3326         while (size >= 4) {
3327                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3328                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3329                 offset += 4;
3330                 size -= 4;
3331         }
3332
3333         while (size >= 2) {
3334                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3335                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3336                 offset += 2;
3337                 size -= 2;
3338         }
3339
3340         while (size >= 1) {
3341                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3342                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3343                 offset += 1;
3344                 size -= 1;
3345         }
3346
3347         return TRUE;
3348 }
3349
3350 /*
3351  * Emit code to copy a valuetype of type @klass whose address is stored in
3352  * @src->dreg to memory whose address is stored at @dest->dreg.
3353  */
3354 void
3355 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3356 {
3357         MonoInst *iargs [4];
3358         int n;
3359         guint32 align = 0;
3360         MonoMethod *memcpy_method;
3361         MonoInst *size_ins = NULL;
3362         MonoInst *memcpy_ins = NULL;
3363
3364         g_assert (klass);
3365         if (cfg->gshared)
3366                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3367
3368         /*
3369          * This check breaks with spilled vars... need to handle it during verification anyway.
3370          * g_assert (klass && klass == src->klass && klass == dest->klass);
3371          */
3372
3373         if (mini_is_gsharedvt_klass (klass)) {
3374                 g_assert (!native);
3375                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3376                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3377         }
3378
3379         if (native)
3380                 n = mono_class_native_size (klass, &align);
3381         else
3382                 n = mono_class_value_size (klass, &align);
3383
3384         /* if native is true there should be no references in the struct */
3385         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3386                 /* Avoid barriers when storing to the stack */
3387                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3388                           (dest->opcode == OP_LDADDR))) {
3389                         int context_used;
3390
3391                         iargs [0] = dest;
3392                         iargs [1] = src;
3393
3394                         context_used = mini_class_check_context_used (cfg, klass);
3395
3396                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3397                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3398                                 return;
3399                         } else if (context_used) {
3400                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3401                         }  else {
3402                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3403                                 if (!cfg->compile_aot)
3404                                         mono_class_compute_gc_descriptor (klass);
3405                         }
3406
3407                         if (size_ins)
3408                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3409                         else
3410                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3411                         return;
3412                 }
3413         }
3414
3415         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3416                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3417                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3418         } else {
3419                 iargs [0] = dest;
3420                 iargs [1] = src;
3421                 if (size_ins)
3422                         iargs [2] = size_ins;
3423                 else
3424                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3425                 
3426                 memcpy_method = get_memcpy_method ();
3427                 if (memcpy_ins)
3428                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3429                 else
3430                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3431         }
3432 }
3433
3434 static MonoMethod*
3435 get_memset_method (void)
3436 {
3437         static MonoMethod *memset_method = NULL;
3438         if (!memset_method) {
3439                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3440                 if (!memset_method)
3441                         g_error ("Old corlib found. Install a new one");
3442         }
3443         return memset_method;
3444 }
3445
3446 void
3447 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3448 {
3449         MonoInst *iargs [3];
3450         int n;
3451         guint32 align;
3452         MonoMethod *memset_method;
3453         MonoInst *size_ins = NULL;
3454         MonoInst *bzero_ins = NULL;
3455         static MonoMethod *bzero_method;
3456
3457         /* FIXME: Optimize this for the case when dest is an LDADDR */
3458         mono_class_init (klass);
3459         if (mini_is_gsharedvt_klass (klass)) {
3460                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3461                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3462                 if (!bzero_method)
3463                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3464                 g_assert (bzero_method);
3465                 iargs [0] = dest;
3466                 iargs [1] = size_ins;
3467                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3468                 return;
3469         }
3470
3471         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3472
3473         n = mono_class_value_size (klass, &align);
3474
3475         if (n <= sizeof (gpointer) * 8) {
3476                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3477         }
3478         else {
3479                 memset_method = get_memset_method ();
3480                 iargs [0] = dest;
3481                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3482                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3483                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3484         }
3485 }
3486
3487 /*
3488  * emit_get_rgctx:
3489  *
3490  *   Emit IR to return either the this pointer for instance method,
3491  * or the mrgctx for static methods.
3492  */
3493 static MonoInst*
3494 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3495 {
3496         MonoInst *this_ins = NULL;
3497
3498         g_assert (cfg->gshared);
3499
3500         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3501                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3502                         !method->klass->valuetype)
3503                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3504
3505         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3506                 MonoInst *mrgctx_loc, *mrgctx_var;
3507
3508                 g_assert (!this_ins);
3509                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3510
3511                 mrgctx_loc = mono_get_vtable_var (cfg);
3512                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3513
3514                 return mrgctx_var;
3515         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3516                 MonoInst *vtable_loc, *vtable_var;
3517
3518                 g_assert (!this_ins);
3519
3520                 vtable_loc = mono_get_vtable_var (cfg);
3521                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3522
3523                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3524                         MonoInst *mrgctx_var = vtable_var;
3525                         int vtable_reg;
3526
3527                         vtable_reg = alloc_preg (cfg);
3528                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3529                         vtable_var->type = STACK_PTR;
3530                 }
3531
3532                 return vtable_var;
3533         } else {
3534                 MonoInst *ins;
3535                 int vtable_reg;
3536         
3537                 vtable_reg = alloc_preg (cfg);
3538                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3539                 return ins;
3540         }
3541 }
3542
3543 static MonoJumpInfoRgctxEntry *
3544 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3545 {
3546         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3547         res->method = method;
3548         res->in_mrgctx = in_mrgctx;
3549         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3550         res->data->type = patch_type;
3551         res->data->data.target = patch_data;
3552         res->info_type = info_type;
3553
3554         return res;
3555 }
3556
3557 static inline MonoInst*
3558 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3559 {
3560         MonoInst *args [16];
3561         MonoInst *call;
3562
3563         // FIXME: No fastpath since the slot is not a compile time constant
3564         args [0] = rgctx;
3565         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3566         if (entry->in_mrgctx)
3567                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3568         else
3569                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3570         return call;
3571 #if 0
3572         /*
3573          * FIXME: This can be called during decompose, which is a problem since it creates
3574          * new bblocks.
3575          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3576          */
3577         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3578         gboolean mrgctx;
3579         MonoBasicBlock *is_null_bb, *end_bb;
3580         MonoInst *res, *ins, *call;
3581         MonoInst *args[16];
3582
3583         slot = mini_get_rgctx_entry_slot (entry);
3584
3585         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3586         index = MONO_RGCTX_SLOT_INDEX (slot);
3587         if (mrgctx)
3588                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3589         for (depth = 0; ; ++depth) {
3590                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3591
3592                 if (index < size - 1)
3593                         break;
3594                 index -= size - 1;
3595         }
3596
3597         NEW_BBLOCK (cfg, end_bb);
3598         NEW_BBLOCK (cfg, is_null_bb);
3599
3600         if (mrgctx) {
3601                 rgctx_reg = rgctx->dreg;
3602         } else {
3603                 rgctx_reg = alloc_preg (cfg);
3604
3605                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3606                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3607                 NEW_BBLOCK (cfg, is_null_bb);
3608
3609                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3610                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3611         }
3612
3613         for (i = 0; i < depth; ++i) {
3614                 int array_reg = alloc_preg (cfg);
3615
3616                 /* load ptr to next array */
3617                 if (mrgctx && i == 0)
3618                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3619                 else
3620                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3621                 rgctx_reg = array_reg;
3622                 /* is the ptr null? */
3623                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3624                 /* if yes, jump to actual trampoline */
3625                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3626         }
3627
3628         /* fetch slot */
3629         val_reg = alloc_preg (cfg);
3630         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3631         /* is the slot null? */
3632         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3633         /* if yes, jump to actual trampoline */
3634         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3635
3636         /* Fastpath */
3637         res_reg = alloc_preg (cfg);
3638         MONO_INST_NEW (cfg, ins, OP_MOVE);
3639         ins->dreg = res_reg;
3640         ins->sreg1 = val_reg;
3641         MONO_ADD_INS (cfg->cbb, ins);
3642         res = ins;
3643         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3644
3645         /* Slowpath */
3646         MONO_START_BB (cfg, is_null_bb);
3647         args [0] = rgctx;
3648         EMIT_NEW_ICONST (cfg, args [1], index);
3649         if (mrgctx)
3650                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3651         else
3652                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3653         MONO_INST_NEW (cfg, ins, OP_MOVE);
3654         ins->dreg = res_reg;
3655         ins->sreg1 = call->dreg;
3656         MONO_ADD_INS (cfg->cbb, ins);
3657         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3658
3659         MONO_START_BB (cfg, end_bb);
3660
3661         return res;
3662 #endif
3663 }
3664
3665 /*
3666  * emit_rgctx_fetch:
3667  *
3668  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3669  * given by RGCTX.
3670  */
3671 static inline MonoInst*
3672 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3673 {
3674         if (cfg->llvm_only)
3675                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3676         else
3677                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3678 }
3679
3680 static MonoInst*
3681 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3682                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3683 {
3684         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_CLASS, klass, rgctx_type);
3685         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3686
3687         return emit_rgctx_fetch (cfg, rgctx, entry);
3688 }
3689
3690 static MonoInst*
3691 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3692                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3693 {
3694         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_SIGNATURE, sig, rgctx_type);
3695         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3696
3697         return emit_rgctx_fetch (cfg, rgctx, entry);
3698 }
3699
3700 static MonoInst*
3701 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3702                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3703 {
3704         MonoJumpInfoGSharedVtCall *call_info;
3705         MonoJumpInfoRgctxEntry *entry;
3706         MonoInst *rgctx;
3707
3708         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3709         call_info->sig = sig;
3710         call_info->method = cmethod;
3711
3712         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_CALL, call_info, rgctx_type);
3713         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3714
3715         return emit_rgctx_fetch (cfg, rgctx, entry);
3716 }
3717
3718 /*
3719  * emit_get_rgctx_virt_method:
3720  *
3721  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3722  */
3723 static MonoInst*
3724 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3725                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3726 {
3727         MonoJumpInfoVirtMethod *info;
3728         MonoJumpInfoRgctxEntry *entry;
3729         MonoInst *rgctx;
3730
3731         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3732         info->klass = klass;
3733         info->method = virt_method;
3734
3735         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_VIRT_METHOD, info, rgctx_type);
3736         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3737
3738         return emit_rgctx_fetch (cfg, rgctx, entry);
3739 }
3740
3741 static MonoInst*
3742 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3743                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3744 {
3745         MonoJumpInfoRgctxEntry *entry;
3746         MonoInst *rgctx;
3747
3748         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_METHOD, info, MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO);
3749         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3750
3751         return emit_rgctx_fetch (cfg, rgctx, entry);
3752 }
3753
3754 /*
3755  * emit_get_rgctx_method:
3756  *
3757  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3758  * normal constants, else emit a load from the rgctx.
3759  */
3760 static MonoInst*
3761 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3762                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3763 {
3764         if (!context_used) {
3765                 MonoInst *ins;
3766
3767                 switch (rgctx_type) {
3768                 case MONO_RGCTX_INFO_METHOD:
3769                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3770                         return ins;
3771                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3772                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3773                         return ins;
3774                 default:
3775                         g_assert_not_reached ();
3776                 }
3777         } else {
3778                 MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
3779                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3780
3781                 return emit_rgctx_fetch (cfg, rgctx, entry);
3782         }
3783 }
3784
3785 static MonoInst*
3786 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3787                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3788 {
3789         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_FIELD, field, rgctx_type);
3790         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3791
3792         return emit_rgctx_fetch (cfg, rgctx, entry);
3793 }
3794
3795 static int
3796 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3797 {
3798         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3799         MonoRuntimeGenericContextInfoTemplate *template_;
3800         int i, idx;
3801
3802         g_assert (info);
3803
3804         for (i = 0; i < info->num_entries; ++i) {
3805                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3806
3807                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3808                         return i;
3809         }
3810
3811         if (info->num_entries == info->count_entries) {
3812                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3813                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3814
3815                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3816
3817                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3818                 info->entries = new_entries;
3819                 info->count_entries = new_count_entries;
3820         }
3821
3822         idx = info->num_entries;
3823         template_ = &info->entries [idx];
3824         template_->info_type = rgctx_type;
3825         template_->data = data;
3826
3827         info->num_entries ++;
3828
3829         return idx;
3830 }
3831
3832 /*
3833  * emit_get_gsharedvt_info:
3834  *
3835  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3836  */
3837 static MonoInst*
3838 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3839 {
3840         MonoInst *ins;
3841         int idx, dreg;
3842
3843         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3844         /* Load info->entries [idx] */
3845         dreg = alloc_preg (cfg);
3846         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3847
3848         return ins;
3849 }
3850
3851 static MonoInst*
3852 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3853 {
3854         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3855 }
3856
3857 /*
3858  * On return the caller must check @klass for load errors.
3859  */
3860 static void
3861 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3862 {
3863         MonoInst *vtable_arg;
3864         int context_used;
3865
3866         context_used = mini_class_check_context_used (cfg, klass);
3867
3868         if (context_used) {
3869                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3870                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3871         } else {
3872                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3873
3874                 if (!vtable)
3875                         return;
3876                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3877         }
3878
3879         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3880                 MonoInst *ins;
3881
3882                 /*
3883                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3884                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3885                  */
3886                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3887                 ins->sreg1 = vtable_arg->dreg;
3888                 MONO_ADD_INS (cfg->cbb, ins);
3889         } else {
3890                 static int byte_offset = -1;
3891                 static guint8 bitmask;
3892                 int bits_reg, inited_reg;
3893                 MonoBasicBlock *inited_bb;
3894                 MonoInst *args [16];
3895
3896                 if (byte_offset < 0)
3897                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3898
3899                 bits_reg = alloc_ireg (cfg);
3900                 inited_reg = alloc_ireg (cfg);
3901
3902                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3903                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3904
3905                 NEW_BBLOCK (cfg, inited_bb);
3906
3907                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3908                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3909
3910                 args [0] = vtable_arg;
3911                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3912
3913                 MONO_START_BB (cfg, inited_bb);
3914         }
3915 }
3916
3917 static void
3918 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3919 {
3920         MonoInst *ins;
3921
3922         if (cfg->gen_seq_points && cfg->method == method) {
3923                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3924                 if (nonempty_stack)
3925                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3926                 MONO_ADD_INS (cfg->cbb, ins);
3927         }
3928 }
3929
3930 static void
3931 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3932 {
3933         if (mini_get_debug_options ()->better_cast_details) {
3934                 int vtable_reg = alloc_preg (cfg);
3935                 int klass_reg = alloc_preg (cfg);
3936                 MonoBasicBlock *is_null_bb = NULL;
3937                 MonoInst *tls_get;
3938                 int to_klass_reg, context_used;
3939
3940                 if (null_check) {
3941                         NEW_BBLOCK (cfg, is_null_bb);
3942
3943                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3944                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3945                 }
3946
3947                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3948                 if (!tls_get) {
3949                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3950                         exit (1);
3951                 }
3952
3953                 MONO_ADD_INS (cfg->cbb, tls_get);
3954                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3955                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3956
3957                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3958
3959                 context_used = mini_class_check_context_used (cfg, klass);
3960                 if (context_used) {
3961                         MonoInst *class_ins;
3962
3963                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3964                         to_klass_reg = class_ins->dreg;
3965                 } else {
3966                         to_klass_reg = alloc_preg (cfg);
3967                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3968                 }
3969                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3970
3971                 if (null_check)
3972                         MONO_START_BB (cfg, is_null_bb);
3973         }
3974 }
3975
3976 static void
3977 reset_cast_details (MonoCompile *cfg)
3978 {
3979         /* Reset the variables holding the cast details */
3980         if (mini_get_debug_options ()->better_cast_details) {
3981                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3982
3983                 MONO_ADD_INS (cfg->cbb, tls_get);
3984                 /* It is enough to reset the from field */
3985                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3986         }
3987 }
3988
3989 /*
3990  * On return the caller must check @array_class for load errors
3991  */
3992 static void
3993 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3994 {
3995         int vtable_reg = alloc_preg (cfg);
3996         int context_used;
3997
3998         context_used = mini_class_check_context_used (cfg, array_class);
3999
4000         save_cast_details (cfg, array_class, obj->dreg, FALSE);
4001
4002         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4003
4004         if (cfg->opt & MONO_OPT_SHARED) {
4005                 int class_reg = alloc_preg (cfg);
4006                 MonoInst *ins;
4007
4008                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4009                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
4010                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
4011         } else if (context_used) {
4012                 MonoInst *vtable_ins;
4013
4014                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
4015                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
4016         } else {
4017                 if (cfg->compile_aot) {
4018                         int vt_reg;
4019                         MonoVTable *vtable;
4020
4021                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4022                                 return;
4023                         vt_reg = alloc_preg (cfg);
4024                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
4025                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
4026                 } else {
4027                         MonoVTable *vtable;
4028                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4029                                 return;
4030                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
4031                 }
4032         }
4033         
4034         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
4035
4036         reset_cast_details (cfg);
4037 }
4038
4039 /**
4040  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
4041  * generic code is generated.
4042  */
4043 static MonoInst*
4044 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4045 {
4046         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4047
4048         if (context_used) {
4049                 MonoInst *rgctx, *addr;
4050
4051                 /* FIXME: What if the class is shared?  We might not
4052                    have to get the address of the method from the
4053                    RGCTX. */
4054                 addr = emit_get_rgctx_method (cfg, context_used, method,
4055                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4056                 if (cfg->llvm_only) {
4057                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
4058                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4059                 } else {
4060                         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4061
4062                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4063                 }
4064         } else {
4065                 gboolean pass_vtable, pass_mrgctx;
4066                 MonoInst *rgctx_arg = NULL;
4067
4068                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4069                 g_assert (!pass_mrgctx);
4070
4071                 if (pass_vtable) {
4072                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4073
4074                         g_assert (vtable);
4075                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4076                 }
4077
4078                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4079         }
4080 }
4081
4082 static MonoInst*
4083 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4084 {
4085         MonoInst *add;
4086         int obj_reg;
4087         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4088         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4089         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4090         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4091
4092         obj_reg = sp [0]->dreg;
4093         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4094         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4095
4096         /* FIXME: generics */
4097         g_assert (klass->rank == 0);
4098                         
4099         // Check rank == 0
4100         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4101         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4102
4103         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4104         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4105
4106         if (context_used) {
4107                 MonoInst *element_class;
4108
4109                 /* This assertion is from the unboxcast insn */
4110                 g_assert (klass->rank == 0);
4111
4112                 element_class = emit_get_rgctx_klass (cfg, context_used,
4113                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4114
4115                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4116                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4117         } else {
4118                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4119                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4120                 reset_cast_details (cfg);
4121         }
4122
4123         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4124         MONO_ADD_INS (cfg->cbb, add);
4125         add->type = STACK_MP;
4126         add->klass = klass;
4127
4128         return add;
4129 }
4130
4131 static MonoInst*
4132 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4133 {
4134         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4135         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4136         MonoInst *ins;
4137         int dreg, addr_reg;
4138
4139         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4140
4141         /* obj */
4142         args [0] = obj;
4143
4144         /* klass */
4145         args [1] = klass_inst;
4146
4147         /* CASTCLASS */
4148         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4149
4150         NEW_BBLOCK (cfg, is_ref_bb);
4151         NEW_BBLOCK (cfg, is_nullable_bb);
4152         NEW_BBLOCK (cfg, end_bb);
4153         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4154         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4155         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4156
4157         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4158         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4159
4160         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4161         addr_reg = alloc_dreg (cfg, STACK_MP);
4162
4163         /* Non-ref case */
4164         /* UNBOX */
4165         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4166         MONO_ADD_INS (cfg->cbb, addr);
4167
4168         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4169
4170         /* Ref case */
4171         MONO_START_BB (cfg, is_ref_bb);
4172
4173         /* Save the ref to a temporary */
4174         dreg = alloc_ireg (cfg);
4175         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4176         addr->dreg = addr_reg;
4177         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4178         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4179
4180         /* Nullable case */
4181         MONO_START_BB (cfg, is_nullable_bb);
4182
4183         {
4184                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4185                 MonoInst *unbox_call;
4186                 MonoMethodSignature *unbox_sig;
4187
4188                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4189                 unbox_sig->ret = &klass->byval_arg;
4190                 unbox_sig->param_count = 1;
4191                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4192
4193                 if (cfg->llvm_only)
4194                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
4195                 else
4196                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4197
4198                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4199                 addr->dreg = addr_reg;
4200         }
4201
4202         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4203
4204         /* End */
4205         MONO_START_BB (cfg, end_bb);
4206
4207         /* LDOBJ */
4208         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4209
4210         return ins;
4211 }
4212
4213 /*
4214  * Returns NULL and set the cfg exception on error.
4215  */
4216 static MonoInst*
4217 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4218 {
4219         MonoInst *iargs [2];
4220         void *alloc_ftn;
4221
4222         if (context_used) {
4223                 MonoInst *data;
4224                 MonoRgctxInfoType rgctx_info;
4225                 MonoInst *iargs [2];
4226                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4227
4228                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4229
4230                 if (cfg->opt & MONO_OPT_SHARED)
4231                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4232                 else
4233                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4234                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4235
4236                 if (cfg->opt & MONO_OPT_SHARED) {
4237                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4238                         iargs [1] = data;
4239                         alloc_ftn = ves_icall_object_new;
4240                 } else {
4241                         iargs [0] = data;
4242                         alloc_ftn = ves_icall_object_new_specific;
4243                 }
4244
4245                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4246                         if (known_instance_size) {
4247                                 int size = mono_class_instance_size (klass);
4248                                 if (size < sizeof (MonoObject))
4249                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4250
4251                                 EMIT_NEW_ICONST (cfg, iargs [1], size);
4252                         }
4253                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4254                 }
4255
4256                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4257         }
4258
4259         if (cfg->opt & MONO_OPT_SHARED) {
4260                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4261                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4262
4263                 alloc_ftn = ves_icall_object_new;
4264         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !mono_class_is_ginst (klass)) {
4265                 /* This happens often in argument checking code, eg. throw new FooException... */
4266                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4267                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4268                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4269         } else {
4270                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4271                 MonoMethod *managed_alloc = NULL;
4272                 gboolean pass_lw;
4273
4274                 if (!vtable) {
4275                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4276                         cfg->exception_ptr = klass;
4277                         return NULL;
4278                 }
4279
4280                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4281
4282                 if (managed_alloc) {
4283                         int size = mono_class_instance_size (klass);
4284                         if (size < sizeof (MonoObject))
4285                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4286
4287                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4288                         EMIT_NEW_ICONST (cfg, iargs [1], size);
4289                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4290                 }
4291                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4292                 if (pass_lw) {
4293                         guint32 lw = vtable->klass->instance_size;
4294                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4295                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4296                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4297                 }
4298                 else {
4299                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4300                 }
4301         }
4302
4303         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4304 }
4305         
4306 /*
4307  * Returns NULL and set the cfg exception on error.
4308  */     
4309 static MonoInst*
4310 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4311 {
4312         MonoInst *alloc, *ins;
4313
4314         if (mono_class_is_nullable (klass)) {
4315                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4316
4317                 if (context_used) {
4318                         if (cfg->llvm_only && cfg->gsharedvt) {
4319                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4320                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4321                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4322                         } else {
4323                                 /* FIXME: What if the class is shared?  We might not
4324                                    have to get the method address from the RGCTX. */
4325                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4326                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4327                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4328
4329                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4330                         }
4331                 } else {
4332                         gboolean pass_vtable, pass_mrgctx;
4333                         MonoInst *rgctx_arg = NULL;
4334
4335                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4336                         g_assert (!pass_mrgctx);
4337
4338                         if (pass_vtable) {
4339                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4340
4341                                 g_assert (vtable);
4342                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4343                         }
4344
4345                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4346                 }
4347         }
4348
4349         if (mini_is_gsharedvt_klass (klass)) {
4350                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4351                 MonoInst *res, *is_ref, *src_var, *addr;
4352                 int dreg;
4353
4354                 dreg = alloc_ireg (cfg);
4355
4356                 NEW_BBLOCK (cfg, is_ref_bb);
4357                 NEW_BBLOCK (cfg, is_nullable_bb);
4358                 NEW_BBLOCK (cfg, end_bb);
4359                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4360                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4361                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4362
4363                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4364                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4365
4366                 /* Non-ref case */
4367                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4368                 if (!alloc)
4369                         return NULL;
4370                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4371                 ins->opcode = OP_STOREV_MEMBASE;
4372
4373                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4374                 res->type = STACK_OBJ;
4375                 res->klass = klass;
4376                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4377                 
4378                 /* Ref case */
4379                 MONO_START_BB (cfg, is_ref_bb);
4380
4381                 /* val is a vtype, so has to load the value manually */
4382                 src_var = get_vreg_to_inst (cfg, val->dreg);
4383                 if (!src_var)
4384                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4385                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4386                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4387                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4388
4389                 /* Nullable case */
4390                 MONO_START_BB (cfg, is_nullable_bb);
4391
4392                 {
4393                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4394                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4395                         MonoInst *box_call;
4396                         MonoMethodSignature *box_sig;
4397
4398                         /*
4399                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4400                          * construct that method at JIT time, so have to do things by hand.
4401                          */
4402                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4403                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4404                         box_sig->param_count = 1;
4405                         box_sig->params [0] = &klass->byval_arg;
4406
4407                         if (cfg->llvm_only)
4408                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4409                         else
4410                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4411                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4412                         res->type = STACK_OBJ;
4413                         res->klass = klass;
4414                 }
4415
4416                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4417
4418                 MONO_START_BB (cfg, end_bb);
4419
4420                 return res;
4421         } else {
4422                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4423                 if (!alloc)
4424                         return NULL;
4425
4426                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4427                 return alloc;
4428         }
4429 }
4430
4431 static gboolean
4432 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4433 {
4434         int i;
4435         MonoGenericContainer *container;
4436         MonoGenericInst *ginst;
4437
4438         if (mono_class_is_ginst (klass)) {
4439                 container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
4440                 ginst = mono_class_get_generic_class (klass)->context.class_inst;
4441         } else if (mono_class_is_gtd (klass) && context_used) {
4442                 container = mono_class_get_generic_container (klass);
4443                 ginst = container->context.class_inst;
4444         } else {
4445                 return FALSE;
4446         }
4447
4448         for (i = 0; i < container->type_argc; ++i) {
4449                 MonoType *type;
4450                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4451                         continue;
4452                 type = ginst->type_argv [i];
4453                 if (mini_type_is_reference (type))
4454                         return TRUE;
4455         }
4456         return FALSE;
4457 }
4458
4459 static GHashTable* direct_icall_type_hash;
4460
4461 static gboolean
4462 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4463 {
4464         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4465         if (!direct_icalls_enabled (cfg))
4466                 return FALSE;
4467
4468         /*
4469          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4470          * Whitelist a few icalls for now.
4471          */
4472         if (!direct_icall_type_hash) {
4473                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4474
4475                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4476                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4477                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4478                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4479                 mono_memory_barrier ();
4480                 direct_icall_type_hash = h;
4481         }
4482
4483         if (cmethod->klass == mono_defaults.math_class)
4484                 return TRUE;
4485         /* No locking needed */
4486         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4487                 return TRUE;
4488         return FALSE;
4489 }
4490
4491 static gboolean
4492 method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
4493 {
4494         if (cmethod->klass == mono_defaults.systemtype_class) {
4495                 if (!strcmp (cmethod->name, "GetType"))
4496                         return TRUE;
4497         }
4498         return FALSE;
4499 }
4500
4501 #define is_complex_isinst(klass) (mono_class_is_interface (klass) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || mono_class_is_sealed (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
4502
4503 static MonoInst*
4504 emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4505 {
4506         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4507         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4508 }
4509
4510 static MonoInst*
4511 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4512 {
4513         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
4514         MonoInst *res;
4515
4516         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4517         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4518         reset_cast_details (cfg);
4519
4520         return res;
4521 }
4522
4523 static int
4524 get_castclass_cache_idx (MonoCompile *cfg)
4525 {
4526         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4527         cfg->castclass_cache_index ++;
4528         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4529 }
4530
4531
4532 static MonoInst*
4533 emit_isinst_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4534 {
4535         MonoInst *args [3];
4536         int idx;
4537
4538         args [0] = obj; /* obj */
4539         EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
4540
4541         idx = get_castclass_cache_idx (cfg); /* inline cache*/
4542         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4543
4544         return emit_isinst_with_cache (cfg, klass, args);
4545 }
4546
4547 static MonoInst*
4548 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4549 {
4550         MonoInst *args [3];
4551         int idx;
4552
4553         /* obj */
4554         args [0] = obj;
4555
4556         /* klass */
4557         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4558
4559         /* inline cache*/
4560         idx = get_castclass_cache_idx (cfg);
4561         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4562
4563         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4564         return emit_castclass_with_cache (cfg, klass, args);
4565 }
4566
4567 /*
4568  * Returns NULL and set the cfg exception on error.
4569  */
4570 static MonoInst*
4571 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4572 {
4573         MonoBasicBlock *is_null_bb;
4574         int obj_reg = src->dreg;
4575         int vtable_reg = alloc_preg (cfg);
4576         MonoInst *klass_inst = NULL;
4577
4578         if (MONO_INS_IS_PCONST_NULL (src))
4579                 return src;
4580
4581         if (context_used) {
4582                 MonoInst *args [3];
4583
4584                 if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4585                         MonoInst *cache_ins;
4586
4587                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4588
4589                         /* obj */
4590                         args [0] = src;
4591
4592                         /* klass - it's the second element of the cache entry*/
4593                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4594
4595                         /* cache */
4596                         args [2] = cache_ins;
4597
4598                         return emit_castclass_with_cache (cfg, klass, args);
4599                 }
4600
4601                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4602         }
4603
4604         NEW_BBLOCK (cfg, is_null_bb);
4605
4606         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4607         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4608
4609         save_cast_details (cfg, klass, obj_reg, FALSE);
4610
4611         if (mono_class_is_interface (klass)) {
4612                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4613                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4614         } else {
4615                 int klass_reg = alloc_preg (cfg);
4616
4617                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4618
4619                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
4620                         /* the remoting code is broken, access the class for now */
4621                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4622                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4623                                 if (!vt) {
4624                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4625                                         cfg->exception_ptr = klass;
4626                                         return NULL;
4627                                 }
4628                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4629                         } else {
4630                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4631                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4632                         }
4633                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4634                 } else {
4635                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4636                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4637                 }
4638         }
4639
4640         MONO_START_BB (cfg, is_null_bb);
4641
4642         reset_cast_details (cfg);
4643
4644         return src;
4645 }
4646
4647 /*
4648  * Returns NULL and set the cfg exception on error.
4649  */
4650 static MonoInst*
4651 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4652 {
4653         MonoInst *ins;
4654         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4655         int obj_reg = src->dreg;
4656         int vtable_reg = alloc_preg (cfg);
4657         int res_reg = alloc_ireg_ref (cfg);
4658         MonoInst *klass_inst = NULL;
4659
4660         if (context_used) {
4661                 MonoInst *args [3];
4662
4663                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4664                         MonoInst *cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4665
4666                         args [0] = src; /* obj */
4667
4668                         /* klass - it's the second element of the cache entry*/
4669                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4670
4671                         args [2] = cache_ins; /* cache */
4672                         return emit_isinst_with_cache (cfg, klass, args);
4673                 }
4674
4675                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4676         }
4677
4678         NEW_BBLOCK (cfg, is_null_bb);
4679         NEW_BBLOCK (cfg, false_bb);
4680         NEW_BBLOCK (cfg, end_bb);
4681
4682         /* Do the assignment at the beginning, so the other assignment can be if converted */
4683         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4684         ins->type = STACK_OBJ;
4685         ins->klass = klass;
4686
4687         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4688         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4689
4690         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4691
4692         if (mono_class_is_interface (klass)) {
4693                 g_assert (!context_used);
4694                 /* the is_null_bb target simply copies the input register to the output */
4695                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4696         } else {
4697                 int klass_reg = alloc_preg (cfg);
4698
4699                 if (klass->rank) {
4700                         int rank_reg = alloc_preg (cfg);
4701                         int eclass_reg = alloc_preg (cfg);
4702
4703                         g_assert (!context_used);
4704                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4705                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4706                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4707                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4708                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4709                         if (klass->cast_class == mono_defaults.object_class) {
4710                                 int parent_reg = alloc_preg (cfg);
4711                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4712                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4713                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4714                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4715                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4716                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4717                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4718                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4719                         } else if (klass->cast_class == mono_defaults.enum_class) {
4720                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4721                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4722                         } else if (mono_class_is_interface (klass->cast_class)) {
4723                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4724                         } else {
4725                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4726                                         /* Check that the object is a vector too */
4727                                         int bounds_reg = alloc_preg (cfg);
4728                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4729                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4730                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4731                                 }
4732
4733                                 /* the is_null_bb target simply copies the input register to the output */
4734                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4735                         }
4736                 } else if (mono_class_is_nullable (klass)) {
4737                         g_assert (!context_used);
4738                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4739                         /* the is_null_bb target simply copies the input register to the output */
4740                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4741                 } else {
4742                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
4743                                 g_assert (!context_used);
4744                                 /* the remoting code is broken, access the class for now */
4745                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4746                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4747                                         if (!vt) {
4748                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4749                                                 cfg->exception_ptr = klass;
4750                                                 return NULL;
4751                                         }
4752                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4753                                 } else {
4754                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4755                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4756                                 }
4757                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4758                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4759                         } else {
4760                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4761                                 /* the is_null_bb target simply copies the input register to the output */
4762                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4763                         }
4764                 }
4765         }
4766
4767         MONO_START_BB (cfg, false_bb);
4768
4769         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4770         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4771
4772         MONO_START_BB (cfg, is_null_bb);
4773
4774         MONO_START_BB (cfg, end_bb);
4775
4776         return ins;
4777 }
4778
4779 static MonoInst*
4780 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4781 {
4782         /* This opcode takes as input an object reference and a class, and returns:
4783         0) if the object is an instance of the class,
4784         1) if the object is not instance of the class,
4785         2) if the object is a proxy whose type cannot be determined */
4786
4787         MonoInst *ins;
4788 #ifndef DISABLE_REMOTING
4789         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4790 #else
4791         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4792 #endif
4793         int obj_reg = src->dreg;
4794         int dreg = alloc_ireg (cfg);
4795         int tmp_reg;
4796 #ifndef DISABLE_REMOTING
4797         int klass_reg = alloc_preg (cfg);
4798 #endif
4799
4800         NEW_BBLOCK (cfg, true_bb);
4801         NEW_BBLOCK (cfg, false_bb);
4802         NEW_BBLOCK (cfg, end_bb);
4803 #ifndef DISABLE_REMOTING
4804         NEW_BBLOCK (cfg, false2_bb);
4805         NEW_BBLOCK (cfg, no_proxy_bb);
4806 #endif
4807
4808         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4809         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4810
4811         if (mono_class_is_interface (klass)) {
4812 #ifndef DISABLE_REMOTING
4813                 NEW_BBLOCK (cfg, interface_fail_bb);
4814 #endif
4815
4816                 tmp_reg = alloc_preg (cfg);
4817                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4818 #ifndef DISABLE_REMOTING
4819                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4820                 MONO_START_BB (cfg, interface_fail_bb);
4821                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4822                 
4823                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4824
4825                 tmp_reg = alloc_preg (cfg);
4826                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4827                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4828                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4829 #else
4830                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4831 #endif
4832         } else {
4833 #ifndef DISABLE_REMOTING
4834                 tmp_reg = alloc_preg (cfg);
4835                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4836                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4837
4838                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4839                 tmp_reg = alloc_preg (cfg);
4840                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4841                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4842
4843                 tmp_reg = alloc_preg (cfg);             
4844                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4845                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4846                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4847                 
4848                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4849                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4850
4851                 MONO_START_BB (cfg, no_proxy_bb);
4852
4853                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4854 #else
4855                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4856 #endif
4857         }
4858
4859         MONO_START_BB (cfg, false_bb);
4860
4861         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4862         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4863
4864 #ifndef DISABLE_REMOTING
4865         MONO_START_BB (cfg, false2_bb);
4866
4867         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4868         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4869 #endif
4870
4871         MONO_START_BB (cfg, true_bb);
4872
4873         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4874
4875         MONO_START_BB (cfg, end_bb);
4876
4877         /* FIXME: */
4878         MONO_INST_NEW (cfg, ins, OP_ICONST);
4879         ins->dreg = dreg;
4880         ins->type = STACK_I4;
4881
4882         return ins;
4883 }
4884
4885 static MonoInst*
4886 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4887 {
4888         /* This opcode takes as input an object reference and a class, and returns:
4889         0) if the object is an instance of the class,
4890         1) if the object is a proxy whose type cannot be determined
4891         an InvalidCastException exception is thrown otherwhise*/
4892         
4893         MonoInst *ins;
4894 #ifndef DISABLE_REMOTING
4895         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4896 #else
4897         MonoBasicBlock *ok_result_bb;
4898 #endif
4899         int obj_reg = src->dreg;
4900         int dreg = alloc_ireg (cfg);
4901         int tmp_reg = alloc_preg (cfg);
4902
4903 #ifndef DISABLE_REMOTING
4904         int klass_reg = alloc_preg (cfg);
4905         NEW_BBLOCK (cfg, end_bb);
4906 #endif
4907
4908         NEW_BBLOCK (cfg, ok_result_bb);
4909
4910         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4911         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4912
4913         save_cast_details (cfg, klass, obj_reg, FALSE);
4914
4915         if (mono_class_is_interface (klass)) {
4916 #ifndef DISABLE_REMOTING
4917                 NEW_BBLOCK (cfg, interface_fail_bb);
4918         
4919                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4920                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4921                 MONO_START_BB (cfg, interface_fail_bb);
4922                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4923
4924                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4925
4926                 tmp_reg = alloc_preg (cfg);             
4927                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4928                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4929                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4930                 
4931                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4932                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4933 #else
4934                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4935                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4936                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4937 #endif
4938         } else {
4939 #ifndef DISABLE_REMOTING
4940                 NEW_BBLOCK (cfg, no_proxy_bb);
4941
4942                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4943                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4944                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4945
4946                 tmp_reg = alloc_preg (cfg);
4947                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4948                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4949
4950                 tmp_reg = alloc_preg (cfg);
4951                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4952                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4953                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4954
4955                 NEW_BBLOCK (cfg, fail_1_bb);
4956                 
4957                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4958
4959                 MONO_START_BB (cfg, fail_1_bb);
4960
4961                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4962                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4963
4964                 MONO_START_BB (cfg, no_proxy_bb);
4965
4966                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4967 #else
4968                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4969 #endif
4970         }
4971
4972         MONO_START_BB (cfg, ok_result_bb);
4973
4974         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4975
4976 #ifndef DISABLE_REMOTING
4977         MONO_START_BB (cfg, end_bb);
4978 #endif
4979
4980         /* FIXME: */
4981         MONO_INST_NEW (cfg, ins, OP_ICONST);
4982         ins->dreg = dreg;
4983         ins->type = STACK_I4;
4984
4985         return ins;
4986 }
4987
4988 static G_GNUC_UNUSED MonoInst*
4989 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4990 {
4991         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4992         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4993         gboolean is_i4;
4994
4995         switch (enum_type->type) {
4996         case MONO_TYPE_I8:
4997         case MONO_TYPE_U8:
4998 #if SIZEOF_REGISTER == 8
4999         case MONO_TYPE_I:
5000         case MONO_TYPE_U:
5001 #endif
5002                 is_i4 = FALSE;
5003                 break;
5004         default:
5005                 is_i4 = TRUE;
5006                 break;
5007         }
5008
5009         {
5010                 MonoInst *load, *and_, *cmp, *ceq;
5011                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
5012                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
5013                 int dest_reg = alloc_ireg (cfg);
5014
5015                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
5016                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
5017                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
5018                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
5019
5020                 ceq->type = STACK_I4;
5021
5022                 if (!is_i4) {
5023                         load = mono_decompose_opcode (cfg, load);
5024                         and_ = mono_decompose_opcode (cfg, and_);
5025                         cmp = mono_decompose_opcode (cfg, cmp);
5026                         ceq = mono_decompose_opcode (cfg, ceq);
5027                 }
5028
5029                 return ceq;
5030         }
5031 }
5032
5033 /*
5034  * Returns NULL and set the cfg exception on error.
5035  */
5036 static G_GNUC_UNUSED MonoInst*
5037 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
5038 {
5039         MonoInst *ptr;
5040         int dreg;
5041         gpointer trampoline;
5042         MonoInst *obj, *method_ins, *tramp_ins;
5043         MonoDomain *domain;
5044         guint8 **code_slot;
5045
5046         if (virtual_ && !cfg->llvm_only) {
5047                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
5048                 g_assert (invoke);
5049
5050                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
5051                         return NULL;
5052         }
5053
5054         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5055         if (!obj)
5056                 return NULL;
5057
5058         /* Inline the contents of mono_delegate_ctor */
5059
5060         /* Set target field */
5061         /* Optimize away setting of NULL target */
5062         if (!MONO_INS_IS_PCONST_NULL (target)) {
5063                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5064                 if (cfg->gen_write_barriers) {
5065                         dreg = alloc_preg (cfg);
5066                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5067                         emit_write_barrier (cfg, ptr, target);
5068                 }
5069         }
5070
5071         /* Set method field */
5072         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5073         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5074
5075         /* 
5076          * To avoid looking up the compiled code belonging to the target method
5077          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5078          * store it, and we fill it after the method has been compiled.
5079          */
5080         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5081                 MonoInst *code_slot_ins;
5082
5083                 if (context_used) {
5084                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5085                 } else {
5086                         domain = mono_domain_get ();
5087                         mono_domain_lock (domain);
5088                         if (!domain_jit_info (domain)->method_code_hash)
5089                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5090                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5091                         if (!code_slot) {
5092                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
5093                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5094                         }
5095                         mono_domain_unlock (domain);
5096
5097                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5098                 }
5099                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5100         }
5101
5102         if (cfg->llvm_only) {
5103                 MonoInst *args [16];
5104
5105                 if (virtual_) {
5106                         args [0] = obj;
5107                         args [1] = target;
5108                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5109                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
5110                 } else {
5111                         args [0] = obj;
5112                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
5113                 }
5114
5115                 return obj;
5116         }
5117
5118         if (cfg->compile_aot) {
5119                 MonoDelegateClassMethodPair *del_tramp;
5120
5121                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5122                 del_tramp->klass = klass;
5123                 del_tramp->method = context_used ? NULL : method;
5124                 del_tramp->is_virtual = virtual_;
5125                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5126         } else {
5127                 if (virtual_)
5128                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5129                 else
5130                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5131                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5132         }
5133
5134         /* Set invoke_impl field */
5135         if (virtual_) {
5136                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5137         } else {
5138                 dreg = alloc_preg (cfg);
5139                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5140                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5141
5142                 dreg = alloc_preg (cfg);
5143                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5144                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5145         }
5146
5147         dreg = alloc_preg (cfg);
5148         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
5149         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5150
5151         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5152
5153         return obj;
5154 }
5155
5156 static MonoInst*
5157 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5158 {
5159         MonoJitICallInfo *info;
5160
5161         /* Need to register the icall so it gets an icall wrapper */
5162         info = mono_get_array_new_va_icall (rank);
5163
5164         cfg->flags |= MONO_CFG_HAS_VARARGS;
5165
5166         /* mono_array_new_va () needs a vararg calling convention */
5167         cfg->exception_message = g_strdup ("array-new");
5168         cfg->disable_llvm = TRUE;
5169
5170         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5171         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5172 }
5173
5174 /*
5175  * handle_constrained_gsharedvt_call:
5176  *
5177  *   Handle constrained calls where the receiver is a gsharedvt type.
5178  * Return the instruction representing the call. Set the cfg exception on failure.
5179  */
5180 static MonoInst*
5181 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5182                                                                    gboolean *ref_emit_widen)
5183 {
5184         MonoInst *ins = NULL;
5185         gboolean emit_widen = *ref_emit_widen;
5186
5187         /*
5188          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5189          * 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
5190          * pack the arguments into an array, and do the rest of the work in in an icall.
5191          */
5192         if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5193                 (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)) &&
5194                 (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]))))) {
5195                 MonoInst *args [16];
5196
5197                 /*
5198                  * This case handles calls to
5199                  * - object:ToString()/Equals()/GetHashCode(),
5200                  * - System.IComparable<T>:CompareTo()
5201                  * - System.IEquatable<T>:Equals ()
5202                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5203                  */
5204
5205                 args [0] = sp [0];
5206                 if (mono_method_check_context_used (cmethod))
5207                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5208                 else
5209                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5210                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5211
5212                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5213                 if (fsig->hasthis && fsig->param_count) {
5214                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5215                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5216                         ins->dreg = alloc_preg (cfg);
5217                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5218                         MONO_ADD_INS (cfg->cbb, ins);
5219                         args [4] = ins;
5220
5221                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5222                                 int addr_reg, deref_arg_reg;
5223
5224                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5225                                 deref_arg_reg = alloc_preg (cfg);
5226                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5227                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5228
5229                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5230                                 addr_reg = ins->dreg;
5231                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5232                         } else {
5233                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5234                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5235                         }
5236                 } else {
5237                         EMIT_NEW_ICONST (cfg, args [3], 0);
5238                         EMIT_NEW_ICONST (cfg, args [4], 0);
5239                 }
5240                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5241                 emit_widen = FALSE;
5242
5243                 if (mini_is_gsharedvt_type (fsig->ret)) {
5244                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5245                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5246                         MonoInst *add;
5247
5248                         /* Unbox */
5249                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5250                         MONO_ADD_INS (cfg->cbb, add);
5251                         /* Load value */
5252                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5253                         MONO_ADD_INS (cfg->cbb, ins);
5254                         /* ins represents the call result */
5255                 }
5256         } else {
5257                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5258         }
5259
5260         *ref_emit_widen = emit_widen;
5261
5262         return ins;
5263
5264  exception_exit:
5265         return NULL;
5266 }
5267
5268 static void
5269 mono_emit_load_got_addr (MonoCompile *cfg)
5270 {
5271         MonoInst *getaddr, *dummy_use;
5272
5273         if (!cfg->got_var || cfg->got_var_allocated)
5274                 return;
5275
5276         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5277         getaddr->cil_code = cfg->header->code;
5278         getaddr->dreg = cfg->got_var->dreg;
5279
5280         /* Add it to the start of the first bblock */
5281         if (cfg->bb_entry->code) {
5282                 getaddr->next = cfg->bb_entry->code;
5283                 cfg->bb_entry->code = getaddr;
5284         }
5285         else
5286                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5287
5288         cfg->got_var_allocated = TRUE;
5289
5290         /* 
5291          * Add a dummy use to keep the got_var alive, since real uses might
5292          * only be generated by the back ends.
5293          * Add it to end_bblock, so the variable's lifetime covers the whole
5294          * method.
5295          * It would be better to make the usage of the got var explicit in all
5296          * cases when the backend needs it (i.e. calls, throw etc.), so this
5297          * wouldn't be needed.
5298          */
5299         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5300         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5301 }
5302
5303 static int inline_limit;
5304 static gboolean inline_limit_inited;
5305
5306 static gboolean
5307 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5308 {
5309         MonoMethodHeaderSummary header;
5310         MonoVTable *vtable;
5311 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5312         MonoMethodSignature *sig = mono_method_signature (method);
5313         int i;
5314 #endif
5315
5316         if (cfg->disable_inline)
5317                 return FALSE;
5318         if (cfg->gshared)
5319                 return FALSE;
5320
5321         if (cfg->inline_depth > 10)
5322                 return FALSE;
5323
5324         if (!mono_method_get_header_summary (method, &header))
5325                 return FALSE;
5326
5327         /*runtime, icall and pinvoke are checked by summary call*/
5328         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5329             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5330             (mono_class_is_marshalbyref (method->klass)) ||
5331             header.has_clauses)
5332                 return FALSE;
5333
5334         /* also consider num_locals? */
5335         /* Do the size check early to avoid creating vtables */
5336         if (!inline_limit_inited) {
5337                 if (g_getenv ("MONO_INLINELIMIT"))
5338                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5339                 else
5340                         inline_limit = INLINE_LENGTH_LIMIT;
5341                 inline_limit_inited = TRUE;
5342         }
5343         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5344                 return FALSE;
5345
5346         /*
5347          * if we can initialize the class of the method right away, we do,
5348          * otherwise we don't allow inlining if the class needs initialization,
5349          * since it would mean inserting a call to mono_runtime_class_init()
5350          * inside the inlined code
5351          */
5352         if (!(cfg->opt & MONO_OPT_SHARED)) {
5353                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5354                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5355                         vtable = mono_class_vtable (cfg->domain, method->klass);
5356                         if (!vtable)
5357                                 return FALSE;
5358                         if (!cfg->compile_aot) {
5359                                 MonoError error;
5360                                 if (!mono_runtime_class_init_full (vtable, &error)) {
5361                                         mono_error_cleanup (&error);
5362                                         return FALSE;
5363                                 }
5364                         }
5365                 } else if (mono_class_is_before_field_init (method->klass)) {
5366                         if (cfg->run_cctors && method->klass->has_cctor) {
5367                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5368                                 if (!method->klass->runtime_info)
5369                                         /* No vtable created yet */
5370                                         return FALSE;
5371                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5372                                 if (!vtable)
5373                                         return FALSE;
5374                                 /* This makes so that inline cannot trigger */
5375                                 /* .cctors: too many apps depend on them */
5376                                 /* running with a specific order... */
5377                                 if (! vtable->initialized)
5378                                         return FALSE;
5379                                 MonoError error;
5380                                 if (!mono_runtime_class_init_full (vtable, &error)) {
5381                                         mono_error_cleanup (&error);
5382                                         return FALSE;
5383                                 }
5384                         }
5385                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5386                         if (!method->klass->runtime_info)
5387                                 /* No vtable created yet */
5388                                 return FALSE;
5389                         vtable = mono_class_vtable (cfg->domain, method->klass);
5390                         if (!vtable)
5391                                 return FALSE;
5392                         if (!vtable->initialized)
5393                                 return FALSE;
5394                 }
5395         } else {
5396                 /* 
5397                  * If we're compiling for shared code
5398                  * the cctor will need to be run at aot method load time, for example,
5399                  * or at the end of the compilation of the inlining method.
5400                  */
5401                 if (mono_class_needs_cctor_run (method->klass, NULL) && !mono_class_is_before_field_init (method->klass))
5402                         return FALSE;
5403         }
5404
5405 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5406         if (mono_arch_is_soft_float ()) {
5407                 /* FIXME: */
5408                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5409                         return FALSE;
5410                 for (i = 0; i < sig->param_count; ++i)
5411                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5412                                 return FALSE;
5413         }
5414 #endif
5415
5416         if (g_list_find (cfg->dont_inline, method))
5417                 return FALSE;
5418
5419         return TRUE;
5420 }
5421
5422 static gboolean
5423 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5424 {
5425         if (!cfg->compile_aot) {
5426                 g_assert (vtable);
5427                 if (vtable->initialized)
5428                         return FALSE;
5429         }
5430
5431         if (mono_class_is_before_field_init (klass)) {
5432                 if (cfg->method == method)
5433                         return FALSE;
5434         }
5435
5436         if (!mono_class_needs_cctor_run (klass, method))
5437                 return FALSE;
5438
5439         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5440                 /* The initialization is already done before the method is called */
5441                 return FALSE;
5442
5443         return TRUE;
5444 }
5445
5446 MonoInst*
5447 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5448 {
5449         MonoInst *ins;
5450         guint32 size;
5451         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5452         int context_used;
5453
5454         if (mini_is_gsharedvt_variable_klass (klass)) {
5455                 size = -1;
5456         } else {
5457                 mono_class_init (klass);
5458                 size = mono_class_array_element_size (klass);
5459         }
5460
5461         mult_reg = alloc_preg (cfg);
5462         array_reg = arr->dreg;
5463         index_reg = index->dreg;
5464
5465 #if SIZEOF_REGISTER == 8
5466         /* The array reg is 64 bits but the index reg is only 32 */
5467         if (COMPILE_LLVM (cfg)) {
5468                 /* Not needed */
5469                 index2_reg = index_reg;
5470         } else {
5471                 index2_reg = alloc_preg (cfg);
5472                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5473         }
5474 #else
5475         if (index->type == STACK_I8) {
5476                 index2_reg = alloc_preg (cfg);
5477                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5478         } else {
5479                 index2_reg = index_reg;
5480         }
5481 #endif
5482
5483         if (bcheck)
5484                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5485
5486 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5487         if (size == 1 || size == 2 || size == 4 || size == 8) {
5488                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5489
5490                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5491                 ins->klass = mono_class_get_element_class (klass);
5492                 ins->type = STACK_MP;
5493
5494                 return ins;
5495         }
5496 #endif          
5497
5498         add_reg = alloc_ireg_mp (cfg);
5499
5500         if (size == -1) {
5501                 MonoInst *rgctx_ins;
5502
5503                 /* gsharedvt */
5504                 g_assert (cfg->gshared);
5505                 context_used = mini_class_check_context_used (cfg, klass);
5506                 g_assert (context_used);
5507                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5508                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5509         } else {
5510                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5511         }
5512         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5513         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5514         ins->klass = mono_class_get_element_class (klass);
5515         ins->type = STACK_MP;
5516         MONO_ADD_INS (cfg->cbb, ins);
5517
5518         return ins;
5519 }
5520
5521 static MonoInst*
5522 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5523 {
5524         int bounds_reg = alloc_preg (cfg);
5525         int add_reg = alloc_ireg_mp (cfg);
5526         int mult_reg = alloc_preg (cfg);
5527         int mult2_reg = alloc_preg (cfg);
5528         int low1_reg = alloc_preg (cfg);
5529         int low2_reg = alloc_preg (cfg);
5530         int high1_reg = alloc_preg (cfg);
5531         int high2_reg = alloc_preg (cfg);
5532         int realidx1_reg = alloc_preg (cfg);
5533         int realidx2_reg = alloc_preg (cfg);
5534         int sum_reg = alloc_preg (cfg);
5535         int index1, index2, tmpreg;
5536         MonoInst *ins;
5537         guint32 size;
5538
5539         mono_class_init (klass);
5540         size = mono_class_array_element_size (klass);
5541
5542         index1 = index_ins1->dreg;
5543         index2 = index_ins2->dreg;
5544
5545 #if SIZEOF_REGISTER == 8
5546         /* The array reg is 64 bits but the index reg is only 32 */
5547         if (COMPILE_LLVM (cfg)) {
5548                 /* Not needed */
5549         } else {
5550                 tmpreg = alloc_preg (cfg);
5551                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5552                 index1 = tmpreg;
5553                 tmpreg = alloc_preg (cfg);
5554                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5555                 index2 = tmpreg;
5556         }
5557 #else
5558         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5559         tmpreg = -1;
5560 #endif
5561
5562         /* range checking */
5563         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5564                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5565
5566         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5567                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5568         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5569         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5570                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5571         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5572         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5573
5574         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5575                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5576         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5577         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5578                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5579         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5580         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5581
5582         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5583         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5584         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5585         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5586         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5587
5588         ins->type = STACK_MP;
5589         ins->klass = klass;
5590         MONO_ADD_INS (cfg->cbb, ins);
5591
5592         return ins;
5593 }
5594
5595 static MonoInst*
5596 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5597 {
5598         int rank;
5599         MonoInst *addr;
5600         MonoMethod *addr_method;
5601         int element_size;
5602         MonoClass *eclass = cmethod->klass->element_class;
5603
5604         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5605
5606         if (rank == 1)
5607                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5608
5609         /* emit_ldelema_2 depends on OP_LMUL */
5610         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5611                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5612         }
5613
5614         if (mini_is_gsharedvt_variable_klass (eclass))
5615                 element_size = 0;
5616         else
5617                 element_size = mono_class_array_element_size (eclass);
5618         addr_method = mono_marshal_get_array_address (rank, element_size);
5619         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5620
5621         return addr;
5622 }
5623
5624 static MonoBreakPolicy
5625 always_insert_breakpoint (MonoMethod *method)
5626 {
5627         return MONO_BREAK_POLICY_ALWAYS;
5628 }
5629
5630 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5631
5632 /**
5633  * mono_set_break_policy:
5634  * policy_callback: the new callback function
5635  *
5636  * Allow embedders to decide wherther to actually obey breakpoint instructions
5637  * (both break IL instructions and Debugger.Break () method calls), for example
5638  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5639  * untrusted or semi-trusted code.
5640  *
5641  * @policy_callback will be called every time a break point instruction needs to
5642  * be inserted with the method argument being the method that calls Debugger.Break()
5643  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5644  * if it wants the breakpoint to not be effective in the given method.
5645  * #MONO_BREAK_POLICY_ALWAYS is the default.
5646  */
5647 void
5648 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5649 {
5650         if (policy_callback)
5651                 break_policy_func = policy_callback;
5652         else
5653                 break_policy_func = always_insert_breakpoint;
5654 }
5655
5656 static gboolean
5657 should_insert_brekpoint (MonoMethod *method) {
5658         switch (break_policy_func (method)) {
5659         case MONO_BREAK_POLICY_ALWAYS:
5660                 return TRUE;
5661         case MONO_BREAK_POLICY_NEVER:
5662                 return FALSE;
5663         case MONO_BREAK_POLICY_ON_DBG:
5664                 g_warning ("mdb no longer supported");
5665                 return FALSE;
5666         default:
5667                 g_warning ("Incorrect value returned from break policy callback");
5668                 return FALSE;
5669         }
5670 }
5671
5672 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5673 static MonoInst*
5674 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5675 {
5676         MonoInst *addr, *store, *load;
5677         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5678
5679         /* the bounds check is already done by the callers */
5680         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5681         if (is_set) {
5682                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5683                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5684                 if (mini_type_is_reference (&eklass->byval_arg))
5685                         emit_write_barrier (cfg, addr, load);
5686         } else {
5687                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5688                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5689         }
5690         return store;
5691 }
5692
5693
5694 static gboolean
5695 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5696 {
5697         return mini_type_is_reference (&klass->byval_arg);
5698 }
5699
5700 static MonoInst*
5701 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5702 {
5703         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5704                 !(MONO_INS_IS_PCONST_NULL (sp [2]))) {
5705                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5706                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5707                 MonoInst *iargs [3];
5708
5709                 if (!helper->slot)
5710                         mono_class_setup_vtable (obj_array);
5711                 g_assert (helper->slot);
5712
5713                 if (sp [0]->type != STACK_OBJ)
5714                         return NULL;
5715                 if (sp [2]->type != STACK_OBJ)
5716                         return NULL;
5717
5718                 iargs [2] = sp [2];
5719                 iargs [1] = sp [1];
5720                 iargs [0] = sp [0];
5721
5722                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5723         } else {
5724                 MonoInst *ins;
5725
5726                 if (mini_is_gsharedvt_variable_klass (klass)) {
5727                         MonoInst *addr;
5728
5729                         // FIXME-VT: OP_ICONST optimization
5730                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5731                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5732                         ins->opcode = OP_STOREV_MEMBASE;
5733                 } else if (sp [1]->opcode == OP_ICONST) {
5734                         int array_reg = sp [0]->dreg;
5735                         int index_reg = sp [1]->dreg;
5736                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5737
5738                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5739                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5740
5741                         if (safety_checks)
5742                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5743                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5744                 } else {
5745                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5746                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5747                         if (generic_class_is_reference_type (cfg, klass))
5748                                 emit_write_barrier (cfg, addr, sp [2]);
5749                 }
5750                 return ins;
5751         }
5752 }
5753
5754 static MonoInst*
5755 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5756 {
5757         MonoClass *eklass;
5758         
5759         if (is_set)
5760                 eklass = mono_class_from_mono_type (fsig->params [2]);
5761         else
5762                 eklass = mono_class_from_mono_type (fsig->ret);
5763
5764         if (is_set) {
5765                 return emit_array_store (cfg, eklass, args, FALSE);
5766         } else {
5767                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5768                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5769                 return ins;
5770         }
5771 }
5772
5773 static gboolean
5774 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5775 {
5776         uint32_t align;
5777         int param_size, return_size;
5778
5779         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5780         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5781
5782         if (cfg->verbose_level > 3)
5783                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5784
5785         //Don't allow mixing reference types with value types
5786         if (param_klass->valuetype != return_klass->valuetype) {
5787                 if (cfg->verbose_level > 3)
5788                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5789                 return FALSE;
5790         }
5791
5792         if (!param_klass->valuetype) {
5793                 if (cfg->verbose_level > 3)
5794                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5795                 return TRUE;
5796         }
5797
5798         //That are blitable
5799         if (param_klass->has_references || return_klass->has_references)
5800                 return FALSE;
5801
5802         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5803         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5804                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5805                         if (cfg->verbose_level > 3)
5806                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5807                 return FALSE;
5808         }
5809
5810         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5811                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5812                 if (cfg->verbose_level > 3)
5813                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5814                 return FALSE;
5815         }
5816
5817         param_size = mono_class_value_size (param_klass, &align);
5818         return_size = mono_class_value_size (return_klass, &align);
5819
5820         //We can do it if sizes match
5821         if (param_size == return_size) {
5822                 if (cfg->verbose_level > 3)
5823                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5824                 return TRUE;
5825         }
5826
5827         //No simple way to handle struct if sizes don't match
5828         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5829                 if (cfg->verbose_level > 3)
5830                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5831                 return FALSE;
5832         }
5833
5834         /*
5835          * Same reg size category.
5836          * A quick note on why we don't require widening here.
5837          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5838          *
5839          * Since the source value comes from a function argument, the JIT will already have
5840          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5841          */
5842         if (param_size <= 4 && return_size <= 4) {
5843                 if (cfg->verbose_level > 3)
5844                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5845                 return TRUE;
5846         }
5847
5848         return FALSE;
5849 }
5850
5851 static MonoInst*
5852 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5853 {
5854         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5855         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5856
5857         if (mini_is_gsharedvt_variable_type (fsig->ret))
5858                 return NULL;
5859
5860         //Valuetypes that are semantically equivalent or numbers than can be widened to
5861         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5862                 return args [0];
5863
5864         //Arrays of valuetypes that are semantically equivalent
5865         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5866                 return args [0];
5867
5868         return NULL;
5869 }
5870
5871 static MonoInst*
5872 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5873 {
5874 #ifdef MONO_ARCH_SIMD_INTRINSICS
5875         MonoInst *ins = NULL;
5876
5877         if (cfg->opt & MONO_OPT_SIMD) {
5878                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5879                 if (ins)
5880                         return ins;
5881         }
5882 #endif
5883
5884         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5885 }
5886
5887 static MonoInst*
5888 emit_memory_barrier (MonoCompile *cfg, int kind)
5889 {
5890         MonoInst *ins = NULL;
5891         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5892         MONO_ADD_INS (cfg->cbb, ins);
5893         ins->backend.memory_barrier_kind = kind;
5894
5895         return ins;
5896 }
5897
5898 static MonoInst*
5899 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5900 {
5901         MonoInst *ins = NULL;
5902         int opcode = 0;
5903
5904         /* The LLVM backend supports these intrinsics */
5905         if (cmethod->klass == mono_defaults.math_class) {
5906                 if (strcmp (cmethod->name, "Sin") == 0) {
5907                         opcode = OP_SIN;
5908                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5909                         opcode = OP_COS;
5910                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5911                         opcode = OP_SQRT;
5912                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5913                         opcode = OP_ABS;
5914                 }
5915
5916                 if (opcode && fsig->param_count == 1) {
5917                         MONO_INST_NEW (cfg, ins, opcode);
5918                         ins->type = STACK_R8;
5919                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5920                         ins->sreg1 = args [0]->dreg;
5921                         MONO_ADD_INS (cfg->cbb, ins);
5922                 }
5923
5924                 opcode = 0;
5925                 if (cfg->opt & MONO_OPT_CMOV) {
5926                         if (strcmp (cmethod->name, "Min") == 0) {
5927                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5928                                         opcode = OP_IMIN;
5929                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5930                                         opcode = OP_IMIN_UN;
5931                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5932                                         opcode = OP_LMIN;
5933                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5934                                         opcode = OP_LMIN_UN;
5935                         } else if (strcmp (cmethod->name, "Max") == 0) {
5936                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5937                                         opcode = OP_IMAX;
5938                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5939                                         opcode = OP_IMAX_UN;
5940                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5941                                         opcode = OP_LMAX;
5942                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5943                                         opcode = OP_LMAX_UN;
5944                         }
5945                 }
5946
5947                 if (opcode && fsig->param_count == 2) {
5948                         MONO_INST_NEW (cfg, ins, opcode);
5949                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5950                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5951                         ins->sreg1 = args [0]->dreg;
5952                         ins->sreg2 = args [1]->dreg;
5953                         MONO_ADD_INS (cfg->cbb, ins);
5954                 }
5955         }
5956
5957         return ins;
5958 }
5959
5960 static MonoInst*
5961 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5962 {
5963         if (cmethod->klass == mono_defaults.array_class) {
5964                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5965                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5966                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5967                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5968                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5969                         return emit_array_unsafe_mov (cfg, fsig, args);
5970         }
5971
5972         return NULL;
5973 }
5974
5975 static MonoInst*
5976 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5977 {
5978         MonoInst *ins = NULL;
5979
5980          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5981
5982         if (cmethod->klass == mono_defaults.string_class) {
5983                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5984                         int dreg = alloc_ireg (cfg);
5985                         int index_reg = alloc_preg (cfg);
5986                         int add_reg = alloc_preg (cfg);
5987
5988 #if SIZEOF_REGISTER == 8
5989                         if (COMPILE_LLVM (cfg)) {
5990                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5991                         } else {
5992                                 /* The array reg is 64 bits but the index reg is only 32 */
5993                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5994                         }
5995 #else
5996                         index_reg = args [1]->dreg;
5997 #endif  
5998                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5999
6000 #if defined(TARGET_X86) || defined(TARGET_AMD64)
6001                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
6002                         add_reg = ins->dreg;
6003                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
6004                                                                    add_reg, 0);
6005 #else
6006                         int mult_reg = alloc_preg (cfg);
6007                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
6008                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
6009                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
6010                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
6011 #endif
6012                         type_from_op (cfg, ins, NULL, NULL);
6013                         return ins;
6014                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6015                         int dreg = alloc_ireg (cfg);
6016                         /* Decompose later to allow more optimizations */
6017                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
6018                         ins->type = STACK_I4;
6019                         ins->flags |= MONO_INST_FAULT;
6020                         cfg->cbb->has_array_access = TRUE;
6021                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
6022
6023                         return ins;
6024                 } else 
6025                         return NULL;
6026         } else if (cmethod->klass == mono_defaults.object_class) {
6027                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
6028                         int dreg = alloc_ireg_ref (cfg);
6029                         int vt_reg = alloc_preg (cfg);
6030                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6031                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
6032                         type_from_op (cfg, ins, NULL, NULL);
6033
6034                         return ins;
6035                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
6036                         int dreg = alloc_ireg (cfg);
6037                         int t1 = alloc_ireg (cfg);
6038         
6039                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
6040                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
6041                         ins->type = STACK_I4;
6042
6043                         return ins;
6044                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
6045                         MONO_INST_NEW (cfg, ins, OP_NOP);
6046                         MONO_ADD_INS (cfg->cbb, ins);
6047                         return ins;
6048                 } else
6049                         return NULL;
6050         } else if (cmethod->klass == mono_defaults.array_class) {
6051                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6052                         return emit_array_generic_access (cfg, fsig, args, FALSE);
6053                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6054                         return emit_array_generic_access (cfg, fsig, args, TRUE);
6055
6056 #ifndef MONO_BIG_ARRAYS
6057                 /*
6058                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
6059                  * Array methods.
6060                  */
6061                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
6062                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
6063                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
6064                         int dreg = alloc_ireg (cfg);
6065                         int bounds_reg = alloc_ireg_mp (cfg);
6066                         MonoBasicBlock *end_bb, *szarray_bb;
6067                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
6068
6069                         NEW_BBLOCK (cfg, end_bb);
6070                         NEW_BBLOCK (cfg, szarray_bb);
6071
6072                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
6073                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
6074                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
6075                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
6076                         /* Non-szarray case */
6077                         if (get_length)
6078                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6079                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
6080                         else
6081                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6082                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
6083                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6084                         MONO_START_BB (cfg, szarray_bb);
6085                         /* Szarray case */
6086                         if (get_length)
6087                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6088                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6089                         else
6090                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6091                         MONO_START_BB (cfg, end_bb);
6092
6093                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
6094                         ins->type = STACK_I4;
6095                         
6096                         return ins;
6097                 }
6098 #endif
6099
6100                 if (cmethod->name [0] != 'g')
6101                         return NULL;
6102
6103                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6104                         int dreg = alloc_ireg (cfg);
6105                         int vtable_reg = alloc_preg (cfg);
6106                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6107                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6108                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6109                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6110                         type_from_op (cfg, ins, NULL, NULL);
6111
6112                         return ins;
6113                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6114                         int dreg = alloc_ireg (cfg);
6115
6116                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6117                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6118                         type_from_op (cfg, ins, NULL, NULL);
6119
6120                         return ins;
6121                 } else
6122                         return NULL;
6123         } else if (cmethod->klass == runtime_helpers_class) {
6124                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6125                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6126                         return ins;
6127                 } else
6128                         return NULL;
6129         } else if (cmethod->klass == mono_defaults.monitor_class) {
6130                 gboolean is_enter = FALSE;
6131                 gboolean is_v4 = FALSE;
6132
6133                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 2 && fsig->params [1]->byref) {
6134                         is_enter = TRUE;
6135                         is_v4 = TRUE;
6136                 }
6137                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 1)
6138                         is_enter = TRUE;
6139
6140                 if (is_enter) {
6141                         /*
6142                          * To make async stack traces work, icalls which can block should have a wrapper.
6143                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
6144                          */
6145                         MonoBasicBlock *end_bb;
6146
6147                         NEW_BBLOCK (cfg, end_bb);
6148
6149                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
6150                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
6151                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
6152                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args);
6153                         MONO_START_BB (cfg, end_bb);
6154                         return ins;
6155                 }
6156         } else if (cmethod->klass == mono_defaults.thread_class) {
6157                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6158                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6159                         MONO_ADD_INS (cfg->cbb, ins);
6160                         return ins;
6161                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6162                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6163                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6164                         guint32 opcode = 0;
6165                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6166
6167                         if (fsig->params [0]->type == MONO_TYPE_I1)
6168                                 opcode = OP_LOADI1_MEMBASE;
6169                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6170                                 opcode = OP_LOADU1_MEMBASE;
6171                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6172                                 opcode = OP_LOADI2_MEMBASE;
6173                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6174                                 opcode = OP_LOADU2_MEMBASE;
6175                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6176                                 opcode = OP_LOADI4_MEMBASE;
6177                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6178                                 opcode = OP_LOADU4_MEMBASE;
6179                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6180                                 opcode = OP_LOADI8_MEMBASE;
6181                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6182                                 opcode = OP_LOADR4_MEMBASE;
6183                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6184                                 opcode = OP_LOADR8_MEMBASE;
6185                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6186                                 opcode = OP_LOAD_MEMBASE;
6187
6188                         if (opcode) {
6189                                 MONO_INST_NEW (cfg, ins, opcode);
6190                                 ins->inst_basereg = args [0]->dreg;
6191                                 ins->inst_offset = 0;
6192                                 MONO_ADD_INS (cfg->cbb, ins);
6193
6194                                 switch (fsig->params [0]->type) {
6195                                 case MONO_TYPE_I1:
6196                                 case MONO_TYPE_U1:
6197                                 case MONO_TYPE_I2:
6198                                 case MONO_TYPE_U2:
6199                                 case MONO_TYPE_I4:
6200                                 case MONO_TYPE_U4:
6201                                         ins->dreg = mono_alloc_ireg (cfg);
6202                                         ins->type = STACK_I4;
6203                                         break;
6204                                 case MONO_TYPE_I8:
6205                                 case MONO_TYPE_U8:
6206                                         ins->dreg = mono_alloc_lreg (cfg);
6207                                         ins->type = STACK_I8;
6208                                         break;
6209                                 case MONO_TYPE_I:
6210                                 case MONO_TYPE_U:
6211                                         ins->dreg = mono_alloc_ireg (cfg);
6212 #if SIZEOF_REGISTER == 8
6213                                         ins->type = STACK_I8;
6214 #else
6215                                         ins->type = STACK_I4;
6216 #endif
6217                                         break;
6218                                 case MONO_TYPE_R4:
6219                                 case MONO_TYPE_R8:
6220                                         ins->dreg = mono_alloc_freg (cfg);
6221                                         ins->type = STACK_R8;
6222                                         break;
6223                                 default:
6224                                         g_assert (mini_type_is_reference (fsig->params [0]));
6225                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6226                                         ins->type = STACK_OBJ;
6227                                         break;
6228                                 }
6229
6230                                 if (opcode == OP_LOADI8_MEMBASE)
6231                                         ins = mono_decompose_opcode (cfg, ins);
6232
6233                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6234
6235                                 return ins;
6236                         }
6237                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6238                         guint32 opcode = 0;
6239                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6240
6241                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6242                                 opcode = OP_STOREI1_MEMBASE_REG;
6243                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6244                                 opcode = OP_STOREI2_MEMBASE_REG;
6245                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6246                                 opcode = OP_STOREI4_MEMBASE_REG;
6247                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6248                                 opcode = OP_STOREI8_MEMBASE_REG;
6249                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6250                                 opcode = OP_STORER4_MEMBASE_REG;
6251                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6252                                 opcode = OP_STORER8_MEMBASE_REG;
6253                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6254                                 opcode = OP_STORE_MEMBASE_REG;
6255
6256                         if (opcode) {
6257                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6258
6259                                 MONO_INST_NEW (cfg, ins, opcode);
6260                                 ins->sreg1 = args [1]->dreg;
6261                                 ins->inst_destbasereg = args [0]->dreg;
6262                                 ins->inst_offset = 0;
6263                                 MONO_ADD_INS (cfg->cbb, ins);
6264
6265                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6266                                         ins = mono_decompose_opcode (cfg, ins);
6267
6268                                 return ins;
6269                         }
6270                 }
6271         } else if (cmethod->klass->image == mono_defaults.corlib &&
6272                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6273                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6274                 ins = NULL;
6275
6276 #if SIZEOF_REGISTER == 8
6277                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6278                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6279                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6280                                 ins->dreg = mono_alloc_preg (cfg);
6281                                 ins->sreg1 = args [0]->dreg;
6282                                 ins->type = STACK_I8;
6283                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6284                                 MONO_ADD_INS (cfg->cbb, ins);
6285                         } else {
6286                                 MonoInst *load_ins;
6287
6288                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6289
6290                                 /* 64 bit reads are already atomic */
6291                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6292                                 load_ins->dreg = mono_alloc_preg (cfg);
6293                                 load_ins->inst_basereg = args [0]->dreg;
6294                                 load_ins->inst_offset = 0;
6295                                 load_ins->type = STACK_I8;
6296                                 MONO_ADD_INS (cfg->cbb, load_ins);
6297
6298                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6299
6300                                 ins = load_ins;
6301                         }
6302                 }
6303 #endif
6304
6305                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6306                         MonoInst *ins_iconst;
6307                         guint32 opcode = 0;
6308
6309                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6310                                 opcode = OP_ATOMIC_ADD_I4;
6311                                 cfg->has_atomic_add_i4 = TRUE;
6312                         }
6313 #if SIZEOF_REGISTER == 8
6314                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6315                                 opcode = OP_ATOMIC_ADD_I8;
6316 #endif
6317                         if (opcode) {
6318                                 if (!mono_arch_opcode_supported (opcode))
6319                                         return NULL;
6320                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6321                                 ins_iconst->inst_c0 = 1;
6322                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6323                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6324
6325                                 MONO_INST_NEW (cfg, ins, opcode);
6326                                 ins->dreg = mono_alloc_ireg (cfg);
6327                                 ins->inst_basereg = args [0]->dreg;
6328                                 ins->inst_offset = 0;
6329                                 ins->sreg2 = ins_iconst->dreg;
6330                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6331                                 MONO_ADD_INS (cfg->cbb, ins);
6332                         }
6333                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6334                         MonoInst *ins_iconst;
6335                         guint32 opcode = 0;
6336
6337                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6338                                 opcode = OP_ATOMIC_ADD_I4;
6339                                 cfg->has_atomic_add_i4 = TRUE;
6340                         }
6341 #if SIZEOF_REGISTER == 8
6342                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6343                                 opcode = OP_ATOMIC_ADD_I8;
6344 #endif
6345                         if (opcode) {
6346                                 if (!mono_arch_opcode_supported (opcode))
6347                                         return NULL;
6348                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6349                                 ins_iconst->inst_c0 = -1;
6350                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6351                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6352
6353                                 MONO_INST_NEW (cfg, ins, opcode);
6354                                 ins->dreg = mono_alloc_ireg (cfg);
6355                                 ins->inst_basereg = args [0]->dreg;
6356                                 ins->inst_offset = 0;
6357                                 ins->sreg2 = ins_iconst->dreg;
6358                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6359                                 MONO_ADD_INS (cfg->cbb, ins);
6360                         }
6361                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6362                         guint32 opcode = 0;
6363
6364                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6365                                 opcode = OP_ATOMIC_ADD_I4;
6366                                 cfg->has_atomic_add_i4 = TRUE;
6367                         }
6368 #if SIZEOF_REGISTER == 8
6369                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6370                                 opcode = OP_ATOMIC_ADD_I8;
6371 #endif
6372                         if (opcode) {
6373                                 if (!mono_arch_opcode_supported (opcode))
6374                                         return NULL;
6375                                 MONO_INST_NEW (cfg, ins, opcode);
6376                                 ins->dreg = mono_alloc_ireg (cfg);
6377                                 ins->inst_basereg = args [0]->dreg;
6378                                 ins->inst_offset = 0;
6379                                 ins->sreg2 = args [1]->dreg;
6380                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6381                                 MONO_ADD_INS (cfg->cbb, ins);
6382                         }
6383                 }
6384                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6385                         MonoInst *f2i = NULL, *i2f;
6386                         guint32 opcode, f2i_opcode, i2f_opcode;
6387                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6388                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6389
6390                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6391                             fsig->params [0]->type == MONO_TYPE_R4) {
6392                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6393                                 f2i_opcode = OP_MOVE_F_TO_I4;
6394                                 i2f_opcode = OP_MOVE_I4_TO_F;
6395                                 cfg->has_atomic_exchange_i4 = TRUE;
6396                         }
6397 #if SIZEOF_REGISTER == 8
6398                         else if (is_ref ||
6399                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6400                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6401                                  fsig->params [0]->type == MONO_TYPE_I) {
6402                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6403                                 f2i_opcode = OP_MOVE_F_TO_I8;
6404                                 i2f_opcode = OP_MOVE_I8_TO_F;
6405                         }
6406 #else
6407                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6408                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6409                                 cfg->has_atomic_exchange_i4 = TRUE;
6410                         }
6411 #endif
6412                         else
6413                                 return NULL;
6414
6415                         if (!mono_arch_opcode_supported (opcode))
6416                                 return NULL;
6417
6418                         if (is_float) {
6419                                 /* TODO: Decompose these opcodes instead of bailing here. */
6420                                 if (COMPILE_SOFT_FLOAT (cfg))
6421                                         return NULL;
6422
6423                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6424                                 f2i->dreg = mono_alloc_ireg (cfg);
6425                                 f2i->sreg1 = args [1]->dreg;
6426                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6427                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6428                                 MONO_ADD_INS (cfg->cbb, f2i);
6429                         }
6430
6431                         MONO_INST_NEW (cfg, ins, opcode);
6432                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6433                         ins->inst_basereg = args [0]->dreg;
6434                         ins->inst_offset = 0;
6435                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6436                         MONO_ADD_INS (cfg->cbb, ins);
6437
6438                         switch (fsig->params [0]->type) {
6439                         case MONO_TYPE_I4:
6440                                 ins->type = STACK_I4;
6441                                 break;
6442                         case MONO_TYPE_I8:
6443                                 ins->type = STACK_I8;
6444                                 break;
6445                         case MONO_TYPE_I:
6446 #if SIZEOF_REGISTER == 8
6447                                 ins->type = STACK_I8;
6448 #else
6449                                 ins->type = STACK_I4;
6450 #endif
6451                                 break;
6452                         case MONO_TYPE_R4:
6453                         case MONO_TYPE_R8:
6454                                 ins->type = STACK_R8;
6455                                 break;
6456                         default:
6457                                 g_assert (mini_type_is_reference (fsig->params [0]));
6458                                 ins->type = STACK_OBJ;
6459                                 break;
6460                         }
6461
6462                         if (is_float) {
6463                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6464                                 i2f->dreg = mono_alloc_freg (cfg);
6465                                 i2f->sreg1 = ins->dreg;
6466                                 i2f->type = STACK_R8;
6467                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6468                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6469                                 MONO_ADD_INS (cfg->cbb, i2f);
6470
6471                                 ins = i2f;
6472                         }
6473
6474                         if (cfg->gen_write_barriers && is_ref)
6475                                 emit_write_barrier (cfg, args [0], args [1]);
6476                 }
6477                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6478                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6479                         guint32 opcode, f2i_opcode, i2f_opcode;
6480                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6481                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6482
6483                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6484                             fsig->params [1]->type == MONO_TYPE_R4) {
6485                                 opcode = OP_ATOMIC_CAS_I4;
6486                                 f2i_opcode = OP_MOVE_F_TO_I4;
6487                                 i2f_opcode = OP_MOVE_I4_TO_F;
6488                                 cfg->has_atomic_cas_i4 = TRUE;
6489                         }
6490 #if SIZEOF_REGISTER == 8
6491                         else if (is_ref ||
6492                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6493                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6494                                  fsig->params [1]->type == MONO_TYPE_I) {
6495                                 opcode = OP_ATOMIC_CAS_I8;
6496                                 f2i_opcode = OP_MOVE_F_TO_I8;
6497                                 i2f_opcode = OP_MOVE_I8_TO_F;
6498                         }
6499 #else
6500                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6501                                 opcode = OP_ATOMIC_CAS_I4;
6502                                 cfg->has_atomic_cas_i4 = TRUE;
6503                         }
6504 #endif
6505                         else
6506                                 return NULL;
6507
6508                         if (!mono_arch_opcode_supported (opcode))
6509                                 return NULL;
6510
6511                         if (is_float) {
6512                                 /* TODO: Decompose these opcodes instead of bailing here. */
6513                                 if (COMPILE_SOFT_FLOAT (cfg))
6514                                         return NULL;
6515
6516                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6517                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6518                                 f2i_new->sreg1 = args [1]->dreg;
6519                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6520                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6521                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6522
6523                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6524                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6525                                 f2i_cmp->sreg1 = args [2]->dreg;
6526                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6527                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6528                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6529                         }
6530
6531                         MONO_INST_NEW (cfg, ins, opcode);
6532                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6533                         ins->sreg1 = args [0]->dreg;
6534                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6535                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6536                         MONO_ADD_INS (cfg->cbb, ins);
6537
6538                         switch (fsig->params [1]->type) {
6539                         case MONO_TYPE_I4:
6540                                 ins->type = STACK_I4;
6541                                 break;
6542                         case MONO_TYPE_I8:
6543                                 ins->type = STACK_I8;
6544                                 break;
6545                         case MONO_TYPE_I:
6546 #if SIZEOF_REGISTER == 8
6547                                 ins->type = STACK_I8;
6548 #else
6549                                 ins->type = STACK_I4;
6550 #endif
6551                                 break;
6552                         case MONO_TYPE_R4:
6553                                 ins->type = cfg->r4_stack_type;
6554                                 break;
6555                         case MONO_TYPE_R8:
6556                                 ins->type = STACK_R8;
6557                                 break;
6558                         default:
6559                                 g_assert (mini_type_is_reference (fsig->params [1]));
6560                                 ins->type = STACK_OBJ;
6561                                 break;
6562                         }
6563
6564                         if (is_float) {
6565                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6566                                 i2f->dreg = mono_alloc_freg (cfg);
6567                                 i2f->sreg1 = ins->dreg;
6568                                 i2f->type = STACK_R8;
6569                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6570                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6571                                 MONO_ADD_INS (cfg->cbb, i2f);
6572
6573                                 ins = i2f;
6574                         }
6575
6576                         if (cfg->gen_write_barriers && is_ref)
6577                                 emit_write_barrier (cfg, args [0], args [1]);
6578                 }
6579                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6580                          fsig->params [1]->type == MONO_TYPE_I4) {
6581                         MonoInst *cmp, *ceq;
6582
6583                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6584                                 return NULL;
6585
6586                         /* int32 r = CAS (location, value, comparand); */
6587                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6588                         ins->dreg = alloc_ireg (cfg);
6589                         ins->sreg1 = args [0]->dreg;
6590                         ins->sreg2 = args [1]->dreg;
6591                         ins->sreg3 = args [2]->dreg;
6592                         ins->type = STACK_I4;
6593                         MONO_ADD_INS (cfg->cbb, ins);
6594
6595                         /* bool result = r == comparand; */
6596                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6597                         cmp->sreg1 = ins->dreg;
6598                         cmp->sreg2 = args [2]->dreg;
6599                         cmp->type = STACK_I4;
6600                         MONO_ADD_INS (cfg->cbb, cmp);
6601
6602                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6603                         ceq->dreg = alloc_ireg (cfg);
6604                         ceq->type = STACK_I4;
6605                         MONO_ADD_INS (cfg->cbb, ceq);
6606
6607                         /* *success = result; */
6608                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6609
6610                         cfg->has_atomic_cas_i4 = TRUE;
6611                 }
6612                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6613                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6614
6615                 if (ins)
6616                         return ins;
6617         } else if (cmethod->klass->image == mono_defaults.corlib &&
6618                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6619                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6620                 ins = NULL;
6621
6622                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6623                         guint32 opcode = 0;
6624                         MonoType *t = fsig->params [0];
6625                         gboolean is_ref;
6626                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
6627
6628                         g_assert (t->byref);
6629                         /* t is a byref type, so the reference check is more complicated */
6630                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6631                         if (t->type == MONO_TYPE_I1)
6632                                 opcode = OP_ATOMIC_LOAD_I1;
6633                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6634                                 opcode = OP_ATOMIC_LOAD_U1;
6635                         else if (t->type == MONO_TYPE_I2)
6636                                 opcode = OP_ATOMIC_LOAD_I2;
6637                         else if (t->type == MONO_TYPE_U2)
6638                                 opcode = OP_ATOMIC_LOAD_U2;
6639                         else if (t->type == MONO_TYPE_I4)
6640                                 opcode = OP_ATOMIC_LOAD_I4;
6641                         else if (t->type == MONO_TYPE_U4)
6642                                 opcode = OP_ATOMIC_LOAD_U4;
6643                         else if (t->type == MONO_TYPE_R4)
6644                                 opcode = OP_ATOMIC_LOAD_R4;
6645                         else if (t->type == MONO_TYPE_R8)
6646                                 opcode = OP_ATOMIC_LOAD_R8;
6647 #if SIZEOF_REGISTER == 8
6648                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6649                                 opcode = OP_ATOMIC_LOAD_I8;
6650                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6651                                 opcode = OP_ATOMIC_LOAD_U8;
6652 #else
6653                         else if (t->type == MONO_TYPE_I)
6654                                 opcode = OP_ATOMIC_LOAD_I4;
6655                         else if (is_ref || t->type == MONO_TYPE_U)
6656                                 opcode = OP_ATOMIC_LOAD_U4;
6657 #endif
6658
6659                         if (opcode) {
6660                                 if (!mono_arch_opcode_supported (opcode))
6661                                         return NULL;
6662
6663                                 MONO_INST_NEW (cfg, ins, opcode);
6664                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6665                                 ins->sreg1 = args [0]->dreg;
6666                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6667                                 MONO_ADD_INS (cfg->cbb, ins);
6668
6669                                 switch (t->type) {
6670                                 case MONO_TYPE_BOOLEAN:
6671                                 case MONO_TYPE_I1:
6672                                 case MONO_TYPE_U1:
6673                                 case MONO_TYPE_I2:
6674                                 case MONO_TYPE_U2:
6675                                 case MONO_TYPE_I4:
6676                                 case MONO_TYPE_U4:
6677                                         ins->type = STACK_I4;
6678                                         break;
6679                                 case MONO_TYPE_I8:
6680                                 case MONO_TYPE_U8:
6681                                         ins->type = STACK_I8;
6682                                         break;
6683                                 case MONO_TYPE_I:
6684                                 case MONO_TYPE_U:
6685 #if SIZEOF_REGISTER == 8
6686                                         ins->type = STACK_I8;
6687 #else
6688                                         ins->type = STACK_I4;
6689 #endif
6690                                         break;
6691                                 case MONO_TYPE_R4:
6692                                         ins->type = cfg->r4_stack_type;
6693                                         break;
6694                                 case MONO_TYPE_R8:
6695                                         ins->type = STACK_R8;
6696                                         break;
6697                                 default:
6698                                         g_assert (is_ref);
6699                                         ins->type = STACK_OBJ;
6700                                         break;
6701                                 }
6702                         }
6703                 }
6704
6705                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6706                         guint32 opcode = 0;
6707                         MonoType *t = fsig->params [0];
6708                         gboolean is_ref;
6709
6710                         g_assert (t->byref);
6711                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6712                         if (t->type == MONO_TYPE_I1)
6713                                 opcode = OP_ATOMIC_STORE_I1;
6714                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6715                                 opcode = OP_ATOMIC_STORE_U1;
6716                         else if (t->type == MONO_TYPE_I2)
6717                                 opcode = OP_ATOMIC_STORE_I2;
6718                         else if (t->type == MONO_TYPE_U2)
6719                                 opcode = OP_ATOMIC_STORE_U2;
6720                         else if (t->type == MONO_TYPE_I4)
6721                                 opcode = OP_ATOMIC_STORE_I4;
6722                         else if (t->type == MONO_TYPE_U4)
6723                                 opcode = OP_ATOMIC_STORE_U4;
6724                         else if (t->type == MONO_TYPE_R4)
6725                                 opcode = OP_ATOMIC_STORE_R4;
6726                         else if (t->type == MONO_TYPE_R8)
6727                                 opcode = OP_ATOMIC_STORE_R8;
6728 #if SIZEOF_REGISTER == 8
6729                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6730                                 opcode = OP_ATOMIC_STORE_I8;
6731                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6732                                 opcode = OP_ATOMIC_STORE_U8;
6733 #else
6734                         else if (t->type == MONO_TYPE_I)
6735                                 opcode = OP_ATOMIC_STORE_I4;
6736                         else if (is_ref || t->type == MONO_TYPE_U)
6737                                 opcode = OP_ATOMIC_STORE_U4;
6738 #endif
6739
6740                         if (opcode) {
6741                                 if (!mono_arch_opcode_supported (opcode))
6742                                         return NULL;
6743
6744                                 MONO_INST_NEW (cfg, ins, opcode);
6745                                 ins->dreg = args [0]->dreg;
6746                                 ins->sreg1 = args [1]->dreg;
6747                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6748                                 MONO_ADD_INS (cfg->cbb, ins);
6749
6750                                 if (cfg->gen_write_barriers && is_ref)
6751                                         emit_write_barrier (cfg, args [0], args [1]);
6752                         }
6753                 }
6754
6755                 if (ins)
6756                         return ins;
6757         } else if (cmethod->klass->image == mono_defaults.corlib &&
6758                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6759                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6760                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6761                         if (should_insert_brekpoint (cfg->method)) {
6762                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6763                         } else {
6764                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6765                                 MONO_ADD_INS (cfg->cbb, ins);
6766                         }
6767                         return ins;
6768                 }
6769         } else if (cmethod->klass->image == mono_defaults.corlib &&
6770                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6771                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6772                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6773 #ifdef TARGET_WIN32
6774                         EMIT_NEW_ICONST (cfg, ins, 1);
6775 #else
6776                         EMIT_NEW_ICONST (cfg, ins, 0);
6777 #endif
6778                 }
6779         } else if (cmethod->klass->image == mono_defaults.corlib &&
6780                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6781                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6782                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6783                         /* No stack walks are currently available, so implement this as an intrinsic */
6784                         MonoInst *assembly_ins;
6785
6786                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6787                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6788                         return ins;
6789                 }
6790         } else if (cmethod->klass->image == mono_defaults.corlib &&
6791                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6792                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6793                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6794                         /* No stack walks are currently available, so implement this as an intrinsic */
6795                         MonoInst *method_ins;
6796                         MonoMethod *declaring = cfg->method;
6797
6798                         /* This returns the declaring generic method */
6799                         if (declaring->is_inflated)
6800                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6801                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6802                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6803                         cfg->no_inline = TRUE;
6804                         if (cfg->method != cfg->current_method)
6805                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6806                         return ins;
6807                 }
6808         } else if (cmethod->klass == mono_defaults.math_class) {
6809                 /* 
6810                  * There is general branchless code for Min/Max, but it does not work for 
6811                  * all inputs:
6812                  * http://everything2.com/?node_id=1051618
6813                  */
6814         } else if (cmethod->klass == mono_defaults.systemtype_class && !strcmp (cmethod->name, "op_Equality")) {
6815                 EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg);
6816                 MONO_INST_NEW (cfg, ins, OP_PCEQ);
6817                 ins->dreg = alloc_preg (cfg);
6818                 ins->type = STACK_I4;
6819                 MONO_ADD_INS (cfg->cbb, ins);
6820                 return ins;
6821         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6822                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6823                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6824                                 !strcmp (cmethod->klass->name, "Selector")) ||
6825                            ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
6826                                  !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
6827                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6828                                 !strcmp (cmethod->klass->name, "Selector"))
6829                            ) {
6830                 if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
6831                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6832                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6833                     cfg->compile_aot) {
6834                         MonoInst *pi;
6835                         MonoJumpInfoToken *ji;
6836                         char *s;
6837
6838                         if (args [0]->opcode == OP_GOT_ENTRY) {
6839                                 pi = (MonoInst *)args [0]->inst_p1;
6840                                 g_assert (pi->opcode == OP_PATCH_INFO);
6841                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6842                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6843                         } else {
6844                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6845                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6846                         }
6847
6848                         NULLIFY_INS (args [0]);
6849
6850                         s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
6851                         return_val_if_nok (&cfg->error, NULL);
6852
6853                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6854                         ins->dreg = mono_alloc_ireg (cfg);
6855                         // FIXME: Leaks
6856                         ins->inst_p0 = s;
6857                         MONO_ADD_INS (cfg->cbb, ins);
6858                         return ins;
6859                 }
6860         }
6861
6862 #ifdef MONO_ARCH_SIMD_INTRINSICS
6863         if (cfg->opt & MONO_OPT_SIMD) {
6864                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6865                 if (ins)
6866                         return ins;
6867         }
6868 #endif
6869
6870         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6871         if (ins)
6872                 return ins;
6873
6874         if (COMPILE_LLVM (cfg)) {
6875                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6876                 if (ins)
6877                         return ins;
6878         }
6879
6880         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6881 }
6882
6883 /*
6884  * This entry point could be used later for arbitrary method
6885  * redirection.
6886  */
6887 inline static MonoInst*
6888 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6889                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6890 {
6891         if (method->klass == mono_defaults.string_class) {
6892                 /* managed string allocation support */
6893                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6894                         MonoInst *iargs [2];
6895                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6896                         MonoMethod *managed_alloc = NULL;
6897
6898                         g_assert (vtable); /*Should not fail since it System.String*/
6899 #ifndef MONO_CROSS_COMPILE
6900                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6901 #endif
6902                         if (!managed_alloc)
6903                                 return NULL;
6904                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6905                         iargs [1] = args [0];
6906                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6907                 }
6908         }
6909         return NULL;
6910 }
6911
6912 static void
6913 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6914 {
6915         MonoInst *store, *temp;
6916         int i;
6917
6918         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6919                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6920
6921                 /*
6922                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6923                  * would be different than the MonoInst's used to represent arguments, and
6924                  * the ldelema implementation can't deal with that.
6925                  * Solution: When ldelema is used on an inline argument, create a var for 
6926                  * it, emit ldelema on that var, and emit the saving code below in
6927                  * inline_method () if needed.
6928                  */
6929                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6930                 cfg->args [i] = temp;
6931                 /* This uses cfg->args [i] which is set by the preceeding line */
6932                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6933                 store->cil_code = sp [0]->cil_code;
6934                 sp++;
6935         }
6936 }
6937
6938 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6939 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6940
6941 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6942 static gboolean
6943 check_inline_called_method_name_limit (MonoMethod *called_method)
6944 {
6945         int strncmp_result;
6946         static const char *limit = NULL;
6947         
6948         if (limit == NULL) {
6949                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6950
6951                 if (limit_string != NULL)
6952                         limit = limit_string;
6953                 else
6954                         limit = "";
6955         }
6956
6957         if (limit [0] != '\0') {
6958                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6959
6960                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6961                 g_free (called_method_name);
6962         
6963                 //return (strncmp_result <= 0);
6964                 return (strncmp_result == 0);
6965         } else {
6966                 return TRUE;
6967         }
6968 }
6969 #endif
6970
6971 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6972 static gboolean
6973 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6974 {
6975         int strncmp_result;
6976         static const char *limit = NULL;
6977         
6978         if (limit == NULL) {
6979                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6980                 if (limit_string != NULL) {
6981                         limit = limit_string;
6982                 } else {
6983                         limit = "";
6984                 }
6985         }
6986
6987         if (limit [0] != '\0') {
6988                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6989
6990                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6991                 g_free (caller_method_name);
6992         
6993                 //return (strncmp_result <= 0);
6994                 return (strncmp_result == 0);
6995         } else {
6996                 return TRUE;
6997         }
6998 }
6999 #endif
7000
7001 static void
7002 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
7003 {
7004         static double r8_0 = 0.0;
7005         static float r4_0 = 0.0;
7006         MonoInst *ins;
7007         int t;
7008
7009         rtype = mini_get_underlying_type (rtype);
7010         t = rtype->type;
7011
7012         if (rtype->byref) {
7013                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
7014         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7015                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
7016         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7017                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
7018         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7019                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7020                 ins->type = STACK_R4;
7021                 ins->inst_p0 = (void*)&r4_0;
7022                 ins->dreg = dreg;
7023                 MONO_ADD_INS (cfg->cbb, ins);
7024         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7025                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7026                 ins->type = STACK_R8;
7027                 ins->inst_p0 = (void*)&r8_0;
7028                 ins->dreg = dreg;
7029                 MONO_ADD_INS (cfg->cbb, ins);
7030         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7031                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7032                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7033         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7034                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7035         } else {
7036                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
7037         }
7038 }
7039
7040 static void
7041 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
7042 {
7043         int t;
7044
7045         rtype = mini_get_underlying_type (rtype);
7046         t = rtype->type;
7047
7048         if (rtype->byref) {
7049                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
7050         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7051                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
7052         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7053                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
7054         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7055                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
7056         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7057                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
7058         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7059                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7060                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7061         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7062                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7063         } else {
7064                 emit_init_rvar (cfg, dreg, rtype);
7065         }
7066 }
7067
7068 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
7069 static void
7070 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
7071 {
7072         MonoInst *var = cfg->locals [local];
7073         if (COMPILE_SOFT_FLOAT (cfg)) {
7074                 MonoInst *store;
7075                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
7076                 emit_init_rvar (cfg, reg, type);
7077                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
7078         } else {
7079                 if (init)
7080                         emit_init_rvar (cfg, var->dreg, type);
7081                 else
7082                         emit_dummy_init_rvar (cfg, var->dreg, type);
7083         }
7084 }
7085
7086 /*
7087  * inline_method:
7088  *
7089  * Return the cost of inlining CMETHOD, or zero if it should not be inlined.
7090  */
7091 static int
7092 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
7093                guchar *ip, guint real_offset, gboolean inline_always)
7094 {
7095         MonoError error;
7096         MonoInst *ins, *rvar = NULL;
7097         MonoMethodHeader *cheader;
7098         MonoBasicBlock *ebblock, *sbblock;
7099         int i, costs;
7100         MonoMethod *prev_inlined_method;
7101         MonoInst **prev_locals, **prev_args;
7102         MonoType **prev_arg_types;
7103         guint prev_real_offset;
7104         GHashTable *prev_cbb_hash;
7105         MonoBasicBlock **prev_cil_offset_to_bb;
7106         MonoBasicBlock *prev_cbb;
7107         const unsigned char *prev_ip;
7108         unsigned char *prev_cil_start;
7109         guint32 prev_cil_offset_to_bb_len;
7110         MonoMethod *prev_current_method;
7111         MonoGenericContext *prev_generic_context;
7112         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
7113
7114         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
7115
7116 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
7117         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
7118                 return 0;
7119 #endif
7120 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
7121         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
7122                 return 0;
7123 #endif
7124
7125         if (!fsig)
7126                 fsig = mono_method_signature (cmethod);
7127
7128         if (cfg->verbose_level > 2)
7129                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7130
7131         if (!cmethod->inline_info) {
7132                 cfg->stat_inlineable_methods++;
7133                 cmethod->inline_info = 1;
7134         }
7135
7136         /* allocate local variables */
7137         cheader = mono_method_get_header_checked (cmethod, &error);
7138         if (!cheader) {
7139                 if (inline_always) {
7140                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7141                         mono_error_move (&cfg->error, &error);
7142                 } else {
7143                         mono_error_cleanup (&error);
7144                 }
7145                 return 0;
7146         }
7147
7148         /*Must verify before creating locals as it can cause the JIT to assert.*/
7149         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7150                 mono_metadata_free_mh (cheader);
7151                 return 0;
7152         }
7153
7154         /* allocate space to store the return value */
7155         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7156                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7157         }
7158
7159         prev_locals = cfg->locals;
7160         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7161         for (i = 0; i < cheader->num_locals; ++i)
7162                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7163
7164         /* allocate start and end blocks */
7165         /* This is needed so if the inline is aborted, we can clean up */
7166         NEW_BBLOCK (cfg, sbblock);
7167         sbblock->real_offset = real_offset;
7168
7169         NEW_BBLOCK (cfg, ebblock);
7170         ebblock->block_num = cfg->num_bblocks++;
7171         ebblock->real_offset = real_offset;
7172
7173         prev_args = cfg->args;
7174         prev_arg_types = cfg->arg_types;
7175         prev_inlined_method = cfg->inlined_method;
7176         cfg->inlined_method = cmethod;
7177         cfg->ret_var_set = FALSE;
7178         cfg->inline_depth ++;
7179         prev_real_offset = cfg->real_offset;
7180         prev_cbb_hash = cfg->cbb_hash;
7181         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7182         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7183         prev_cil_start = cfg->cil_start;
7184         prev_ip = cfg->ip;
7185         prev_cbb = cfg->cbb;
7186         prev_current_method = cfg->current_method;
7187         prev_generic_context = cfg->generic_context;
7188         prev_ret_var_set = cfg->ret_var_set;
7189         prev_disable_inline = cfg->disable_inline;
7190
7191         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7192                 virtual_ = TRUE;
7193
7194         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7195
7196         ret_var_set = cfg->ret_var_set;
7197
7198         cfg->inlined_method = prev_inlined_method;
7199         cfg->real_offset = prev_real_offset;
7200         cfg->cbb_hash = prev_cbb_hash;
7201         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7202         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7203         cfg->cil_start = prev_cil_start;
7204         cfg->ip = prev_ip;
7205         cfg->locals = prev_locals;
7206         cfg->args = prev_args;
7207         cfg->arg_types = prev_arg_types;
7208         cfg->current_method = prev_current_method;
7209         cfg->generic_context = prev_generic_context;
7210         cfg->ret_var_set = prev_ret_var_set;
7211         cfg->disable_inline = prev_disable_inline;
7212         cfg->inline_depth --;
7213
7214         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7215                 if (cfg->verbose_level > 2)
7216                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7217                 
7218                 cfg->stat_inlined_methods++;
7219
7220                 /* always add some code to avoid block split failures */
7221                 MONO_INST_NEW (cfg, ins, OP_NOP);
7222                 MONO_ADD_INS (prev_cbb, ins);
7223
7224                 prev_cbb->next_bb = sbblock;
7225                 link_bblock (cfg, prev_cbb, sbblock);
7226
7227                 /* 
7228                  * Get rid of the begin and end bblocks if possible to aid local
7229                  * optimizations.
7230                  */
7231                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7232
7233                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7234                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7235
7236                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7237                         MonoBasicBlock *prev = ebblock->in_bb [0];
7238
7239                         if (prev->next_bb == ebblock) {
7240                                 mono_merge_basic_blocks (cfg, prev, ebblock);
7241                                 cfg->cbb = prev;
7242                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7243                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
7244                                         cfg->cbb = prev_cbb;
7245                                 }
7246                         } else {
7247                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
7248                                 cfg->cbb = ebblock;
7249                         }
7250                 } else {
7251                         /* 
7252                          * Its possible that the rvar is set in some prev bblock, but not in others.
7253                          * (#1835).
7254                          */
7255                         if (rvar) {
7256                                 MonoBasicBlock *bb;
7257
7258                                 for (i = 0; i < ebblock->in_count; ++i) {
7259                                         bb = ebblock->in_bb [i];
7260
7261                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7262                                                 cfg->cbb = bb;
7263
7264                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7265                                         }
7266                                 }
7267                         }
7268
7269                         cfg->cbb = ebblock;
7270                 }
7271
7272                 if (rvar) {
7273                         /*
7274                          * If the inlined method contains only a throw, then the ret var is not 
7275                          * set, so set it to a dummy value.
7276                          */
7277                         if (!ret_var_set)
7278                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7279
7280                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7281                         *sp++ = ins;
7282                 }
7283                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7284                 return costs + 1;
7285         } else {
7286                 if (cfg->verbose_level > 2)
7287                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7288                 cfg->exception_type = MONO_EXCEPTION_NONE;
7289
7290                 /* This gets rid of the newly added bblocks */
7291                 cfg->cbb = prev_cbb;
7292         }
7293         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7294         return 0;
7295 }
7296
7297 /*
7298  * Some of these comments may well be out-of-date.
7299  * Design decisions: we do a single pass over the IL code (and we do bblock 
7300  * splitting/merging in the few cases when it's required: a back jump to an IL
7301  * address that was not already seen as bblock starting point).
7302  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7303  * Complex operations are decomposed in simpler ones right away. We need to let the 
7304  * arch-specific code peek and poke inside this process somehow (except when the 
7305  * optimizations can take advantage of the full semantic info of coarse opcodes).
7306  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7307  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7308  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7309  * opcode with value bigger than OP_LAST.
7310  * At this point the IR can be handed over to an interpreter, a dumb code generator
7311  * or to the optimizing code generator that will translate it to SSA form.
7312  *
7313  * Profiling directed optimizations.
7314  * We may compile by default with few or no optimizations and instrument the code
7315  * or the user may indicate what methods to optimize the most either in a config file
7316  * or through repeated runs where the compiler applies offline the optimizations to 
7317  * each method and then decides if it was worth it.
7318  */
7319
7320 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7321 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7322 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7323 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7324 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7325 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7326 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7327 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
7328
7329 /* offset from br.s -> br like opcodes */
7330 #define BIG_BRANCH_OFFSET 13
7331
7332 static gboolean
7333 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7334 {
7335         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7336
7337         return b == NULL || b == bb;
7338 }
7339
7340 static int
7341 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7342 {
7343         unsigned char *ip = start;
7344         unsigned char *target;
7345         int i;
7346         guint cli_addr;
7347         MonoBasicBlock *bblock;
7348         const MonoOpcode *opcode;
7349
7350         while (ip < end) {
7351                 cli_addr = ip - start;
7352                 i = mono_opcode_value ((const guint8 **)&ip, end);
7353                 if (i < 0)
7354                         UNVERIFIED;
7355                 opcode = &mono_opcodes [i];
7356                 switch (opcode->argument) {
7357                 case MonoInlineNone:
7358                         ip++; 
7359                         break;
7360                 case MonoInlineString:
7361                 case MonoInlineType:
7362                 case MonoInlineField:
7363                 case MonoInlineMethod:
7364                 case MonoInlineTok:
7365                 case MonoInlineSig:
7366                 case MonoShortInlineR:
7367                 case MonoInlineI:
7368                         ip += 5;
7369                         break;
7370                 case MonoInlineVar:
7371                         ip += 3;
7372                         break;
7373                 case MonoShortInlineVar:
7374                 case MonoShortInlineI:
7375                         ip += 2;
7376                         break;
7377                 case MonoShortInlineBrTarget:
7378                         target = start + cli_addr + 2 + (signed char)ip [1];
7379                         GET_BBLOCK (cfg, bblock, target);
7380                         ip += 2;
7381                         if (ip < end)
7382                                 GET_BBLOCK (cfg, bblock, ip);
7383                         break;
7384                 case MonoInlineBrTarget:
7385                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7386                         GET_BBLOCK (cfg, bblock, target);
7387                         ip += 5;
7388                         if (ip < end)
7389                                 GET_BBLOCK (cfg, bblock, ip);
7390                         break;
7391                 case MonoInlineSwitch: {
7392                         guint32 n = read32 (ip + 1);
7393                         guint32 j;
7394                         ip += 5;
7395                         cli_addr += 5 + 4 * n;
7396                         target = start + cli_addr;
7397                         GET_BBLOCK (cfg, bblock, target);
7398                         
7399                         for (j = 0; j < n; ++j) {
7400                                 target = start + cli_addr + (gint32)read32 (ip);
7401                                 GET_BBLOCK (cfg, bblock, target);
7402                                 ip += 4;
7403                         }
7404                         break;
7405                 }
7406                 case MonoInlineR:
7407                 case MonoInlineI8:
7408                         ip += 9;
7409                         break;
7410                 default:
7411                         g_assert_not_reached ();
7412                 }
7413
7414                 if (i == CEE_THROW) {
7415                         unsigned char *bb_start = ip - 1;
7416                         
7417                         /* Find the start of the bblock containing the throw */
7418                         bblock = NULL;
7419                         while ((bb_start >= start) && !bblock) {
7420                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7421                                 bb_start --;
7422                         }
7423                         if (bblock)
7424                                 bblock->out_of_line = 1;
7425                 }
7426         }
7427         return 0;
7428 unverified:
7429 exception_exit:
7430         *pos = ip;
7431         return 1;
7432 }
7433
7434 static inline MonoMethod *
7435 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
7436 {
7437         MonoMethod *method;
7438
7439         mono_error_init (error);
7440
7441         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7442                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7443                 if (context) {
7444                         method = mono_class_inflate_generic_method_checked (method, context, error);
7445                 }
7446         } else {
7447                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
7448         }
7449
7450         return method;
7451 }
7452
7453 static inline MonoMethod *
7454 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7455 {
7456         MonoError error;
7457         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
7458
7459         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
7460                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
7461                 method = NULL;
7462         }
7463
7464         if (!method && !cfg)
7465                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7466
7467         return method;
7468 }
7469
7470 static inline MonoClass*
7471 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7472 {
7473         MonoError error;
7474         MonoClass *klass;
7475
7476         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7477                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7478                 if (context) {
7479                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
7480                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7481                 }
7482         } else {
7483                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7484                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7485         }
7486         if (klass)
7487                 mono_class_init (klass);
7488         return klass;
7489 }
7490
7491 static inline MonoMethodSignature*
7492 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
7493 {
7494         MonoMethodSignature *fsig;
7495
7496         mono_error_init (error);
7497         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7498                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7499         } else {
7500                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
7501                 return_val_if_nok (error, NULL);
7502         }
7503         if (context) {
7504                 fsig = mono_inflate_generic_signature(fsig, context, error);
7505         }
7506         return fsig;
7507 }
7508
7509 static MonoMethod*
7510 throw_exception (void)
7511 {
7512         static MonoMethod *method = NULL;
7513
7514         if (!method) {
7515                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7516                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7517         }
7518         g_assert (method);
7519         return method;
7520 }
7521
7522 static void
7523 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7524 {
7525         MonoMethod *thrower = throw_exception ();
7526         MonoInst *args [1];
7527
7528         EMIT_NEW_PCONST (cfg, args [0], ex);
7529         mono_emit_method_call (cfg, thrower, args, NULL);
7530 }
7531
7532 /*
7533  * Return the original method is a wrapper is specified. We can only access 
7534  * the custom attributes from the original method.
7535  */
7536 static MonoMethod*
7537 get_original_method (MonoMethod *method)
7538 {
7539         if (method->wrapper_type == MONO_WRAPPER_NONE)
7540                 return method;
7541
7542         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7543         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7544                 return NULL;
7545
7546         /* in other cases we need to find the original method */
7547         return mono_marshal_method_from_wrapper (method);
7548 }
7549
7550 static void
7551 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7552 {
7553         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7554         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7555         if (ex)
7556                 emit_throw_exception (cfg, ex);
7557 }
7558
7559 static void
7560 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7561 {
7562         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7563         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7564         if (ex)
7565                 emit_throw_exception (cfg, ex);
7566 }
7567
7568 /*
7569  * Check that the IL instructions at ip are the array initialization
7570  * sequence and return the pointer to the data and the size.
7571  */
7572 static const char*
7573 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7574 {
7575         /*
7576          * newarr[System.Int32]
7577          * dup
7578          * ldtoken field valuetype ...
7579          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7580          */
7581         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7582                 MonoError error;
7583                 guint32 token = read32 (ip + 7);
7584                 guint32 field_token = read32 (ip + 2);
7585                 guint32 field_index = field_token & 0xffffff;
7586                 guint32 rva;
7587                 const char *data_ptr;
7588                 int size = 0;
7589                 MonoMethod *cmethod;
7590                 MonoClass *dummy_class;
7591                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7592                 int dummy_align;
7593
7594                 if (!field) {
7595                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7596                         return NULL;
7597                 }
7598
7599                 *out_field_token = field_token;
7600
7601                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7602                 if (!cmethod)
7603                         return NULL;
7604                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7605                         return NULL;
7606                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7607                 case MONO_TYPE_BOOLEAN:
7608                 case MONO_TYPE_I1:
7609                 case MONO_TYPE_U1:
7610                         size = 1; break;
7611                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7612 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7613                 case MONO_TYPE_CHAR:
7614                 case MONO_TYPE_I2:
7615                 case MONO_TYPE_U2:
7616                         size = 2; break;
7617                 case MONO_TYPE_I4:
7618                 case MONO_TYPE_U4:
7619                 case MONO_TYPE_R4:
7620                         size = 4; break;
7621                 case MONO_TYPE_R8:
7622                 case MONO_TYPE_I8:
7623                 case MONO_TYPE_U8:
7624                         size = 8; break;
7625 #endif
7626                 default:
7627                         return NULL;
7628                 }
7629                 size *= len;
7630                 if (size > mono_type_size (field->type, &dummy_align))
7631                     return NULL;
7632                 *out_size = size;
7633                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7634                 if (!image_is_dynamic (method->klass->image)) {
7635                         field_index = read32 (ip + 2) & 0xffffff;
7636                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7637                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7638                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7639                         /* for aot code we do the lookup on load */
7640                         if (aot && data_ptr)
7641                                 return (const char *)GUINT_TO_POINTER (rva);
7642                 } else {
7643                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7644                         g_assert (!aot);
7645                         data_ptr = mono_field_get_data (field);
7646                 }
7647                 return data_ptr;
7648         }
7649         return NULL;
7650 }
7651
7652 static void
7653 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7654 {
7655         MonoError error;
7656         char *method_fname = mono_method_full_name (method, TRUE);
7657         char *method_code;
7658         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
7659
7660         if (!header) {
7661                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
7662                 mono_error_cleanup (&error);
7663         } else if (header->code_size == 0)
7664                 method_code = g_strdup ("method body is empty.");
7665         else
7666                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7667         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
7668         g_free (method_fname);
7669         g_free (method_code);
7670         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7671 }
7672
7673 static void
7674 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7675 {
7676         MonoInst *ins;
7677         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7678         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7679                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7680                 /* Optimize reg-reg moves away */
7681                 /* 
7682                  * Can't optimize other opcodes, since sp[0] might point to
7683                  * the last ins of a decomposed opcode.
7684                  */
7685                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7686         } else {
7687                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7688         }
7689 }
7690
7691 /*
7692  * ldloca inhibits many optimizations so try to get rid of it in common
7693  * cases.
7694  */
7695 static inline unsigned char *
7696 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7697 {
7698         int local, token;
7699         MonoClass *klass;
7700         MonoType *type;
7701
7702         if (size == 1) {
7703                 local = ip [1];
7704                 ip += 2;
7705         } else {
7706                 local = read16 (ip + 2);
7707                 ip += 4;
7708         }
7709         
7710         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7711                 /* From the INITOBJ case */
7712                 token = read32 (ip + 2);
7713                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7714                 CHECK_TYPELOAD (klass);
7715                 type = mini_get_underlying_type (&klass->byval_arg);
7716                 emit_init_local (cfg, local, type, TRUE);
7717                 return ip + 6;
7718         }
7719  exception_exit:
7720         return NULL;
7721 }
7722
7723 static MonoInst*
7724 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7725 {
7726         MonoInst *icall_args [16];
7727         MonoInst *call_target, *ins, *vtable_ins;
7728         int arg_reg, this_reg, vtable_reg;
7729         gboolean is_iface = mono_class_is_interface (cmethod->klass);
7730         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7731         gboolean variant_iface = FALSE;
7732         guint32 slot;
7733         int offset;
7734
7735         /*
7736          * In llvm-only mode, vtables contain function descriptors instead of
7737          * method addresses/trampolines.
7738          */
7739         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7740
7741         if (is_iface)
7742                 slot = mono_method_get_imt_slot (cmethod);
7743         else
7744                 slot = mono_method_get_vtable_index (cmethod);
7745
7746         this_reg = sp [0]->dreg;
7747
7748         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7749                 variant_iface = TRUE;
7750
7751         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7752                 /*
7753                  * The simplest case, a normal virtual call.
7754                  */
7755                 int slot_reg = alloc_preg (cfg);
7756                 int addr_reg = alloc_preg (cfg);
7757                 int arg_reg = alloc_preg (cfg);
7758                 MonoBasicBlock *non_null_bb;
7759
7760                 vtable_reg = alloc_preg (cfg);
7761                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7762                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7763
7764                 /* Load the vtable slot, which contains a function descriptor. */
7765                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7766
7767                 NEW_BBLOCK (cfg, non_null_bb);
7768
7769                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7770                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7771                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7772
7773                 /* Slow path */
7774                 // FIXME: Make the wrapper use the preserveall cconv
7775                 // FIXME: Use one icall per slot for small slot numbers ?
7776                 icall_args [0] = vtable_ins;
7777                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7778                 /* Make the icall return the vtable slot value to save some code space */
7779                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7780                 ins->dreg = slot_reg;
7781                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7782
7783                 /* Fastpath */
7784                 MONO_START_BB (cfg, non_null_bb);
7785                 /* Load the address + arg from the vtable slot */
7786                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7787                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7788
7789                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7790         }
7791
7792         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7793                 /*
7794                  * A simple interface call
7795                  *
7796                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7797                  * The imt slot contains a function descriptor for a runtime function + arg.
7798                  */
7799                 int slot_reg = alloc_preg (cfg);
7800                 int addr_reg = alloc_preg (cfg);
7801                 int arg_reg = alloc_preg (cfg);
7802                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7803
7804                 vtable_reg = alloc_preg (cfg);
7805                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7806                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7807
7808                 /*
7809                  * The slot is already initialized when the vtable is created so there is no need
7810                  * to check it here.
7811                  */
7812
7813                 /* Load the imt slot, which contains a function descriptor. */
7814                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7815
7816                 /* Load the address + arg of the imt thunk from the imt slot */
7817                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7818                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7819                 /*
7820                  * IMT thunks in llvm-only mode are C functions which take an info argument
7821                  * plus the imt method and return the ftndesc to call.
7822                  */
7823                 icall_args [0] = thunk_arg_ins;
7824                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7825                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7826                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7827
7828                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7829         }
7830
7831         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7832                 /*
7833                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7834                  * dynamically extended as more instantiations are discovered.
7835                  * This handles generic virtual methods both on classes and interfaces.
7836                  */
7837                 int slot_reg = alloc_preg (cfg);
7838                 int addr_reg = alloc_preg (cfg);
7839                 int arg_reg = alloc_preg (cfg);
7840                 int ftndesc_reg = alloc_preg (cfg);
7841                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7842                 MonoBasicBlock *slowpath_bb, *end_bb;
7843
7844                 NEW_BBLOCK (cfg, slowpath_bb);
7845                 NEW_BBLOCK (cfg, end_bb);
7846
7847                 vtable_reg = alloc_preg (cfg);
7848                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7849                 if (is_iface)
7850                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7851                 else
7852                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7853
7854                 /* Load the slot, which contains a function descriptor. */
7855                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7856
7857                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7858                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7859                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7860                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7861
7862                 /* Fastpath */
7863                 /* Same as with iface calls */
7864                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7865                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7866                 icall_args [0] = thunk_arg_ins;
7867                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7868                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7869                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7870                 ftndesc_ins->dreg = ftndesc_reg;
7871                 /*
7872                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7873                  * they don't know about yet. Fall back to the slowpath in that case.
7874                  */
7875                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7876                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7877
7878                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7879
7880                 /* Slowpath */
7881                 MONO_START_BB (cfg, slowpath_bb);
7882                 icall_args [0] = vtable_ins;
7883                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7884                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7885                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7886                 if (is_iface)
7887                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7888                 else
7889                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7890                 ftndesc_ins->dreg = ftndesc_reg;
7891                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7892
7893                 /* Common case */
7894                 MONO_START_BB (cfg, end_bb);
7895                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7896         }
7897
7898         /*
7899          * Non-optimized cases
7900          */
7901         icall_args [0] = sp [0];
7902         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7903
7904         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7905                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7906
7907         arg_reg = alloc_preg (cfg);
7908         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7909         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7910
7911         g_assert (is_gsharedvt);
7912         if (is_iface)
7913                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7914         else
7915                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7916
7917         /*
7918          * Pass the extra argument even if the callee doesn't receive it, most
7919          * calling conventions allow this.
7920          */
7921         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7922 }
7923
7924 static gboolean
7925 is_exception_class (MonoClass *klass)
7926 {
7927         while (klass) {
7928                 if (klass == mono_defaults.exception_class)
7929                         return TRUE;
7930                 klass = klass->parent;
7931         }
7932         return FALSE;
7933 }
7934
7935 /*
7936  * is_jit_optimizer_disabled:
7937  *
7938  *   Determine whenever M's assembly has a DebuggableAttribute with the
7939  * IsJITOptimizerDisabled flag set.
7940  */
7941 static gboolean
7942 is_jit_optimizer_disabled (MonoMethod *m)
7943 {
7944         MonoError error;
7945         MonoAssembly *ass = m->klass->image->assembly;
7946         MonoCustomAttrInfo* attrs;
7947         MonoClass *klass;
7948         int i;
7949         gboolean val = FALSE;
7950
7951         g_assert (ass);
7952         if (ass->jit_optimizer_disabled_inited)
7953                 return ass->jit_optimizer_disabled;
7954
7955         klass = mono_class_try_get_debuggable_attribute_class ();
7956
7957         if (!klass) {
7958                 /* Linked away */
7959                 ass->jit_optimizer_disabled = FALSE;
7960                 mono_memory_barrier ();
7961                 ass->jit_optimizer_disabled_inited = TRUE;
7962                 return FALSE;
7963         }
7964
7965         attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
7966         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7967         if (attrs) {
7968                 for (i = 0; i < attrs->num_attrs; ++i) {
7969                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7970                         const gchar *p;
7971                         MonoMethodSignature *sig;
7972
7973                         if (!attr->ctor || attr->ctor->klass != klass)
7974                                 continue;
7975                         /* Decode the attribute. See reflection.c */
7976                         p = (const char*)attr->data;
7977                         g_assert (read16 (p) == 0x0001);
7978                         p += 2;
7979
7980                         // FIXME: Support named parameters
7981                         sig = mono_method_signature (attr->ctor);
7982                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7983                                 continue;
7984                         /* Two boolean arguments */
7985                         p ++;
7986                         val = *p;
7987                 }
7988                 mono_custom_attrs_free (attrs);
7989         }
7990
7991         ass->jit_optimizer_disabled = val;
7992         mono_memory_barrier ();
7993         ass->jit_optimizer_disabled_inited = TRUE;
7994
7995         return val;
7996 }
7997
7998 static gboolean
7999 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
8000 {
8001         gboolean supported_tail_call;
8002         int i;
8003
8004         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
8005
8006         for (i = 0; i < fsig->param_count; ++i) {
8007                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
8008                         /* These can point to the current method's stack */
8009                         supported_tail_call = FALSE;
8010         }
8011         if (fsig->hasthis && cmethod->klass->valuetype)
8012                 /* this might point to the current method's stack */
8013                 supported_tail_call = FALSE;
8014         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
8015                 supported_tail_call = FALSE;
8016         if (cfg->method->save_lmf)
8017                 supported_tail_call = FALSE;
8018         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
8019                 supported_tail_call = FALSE;
8020         if (call_opcode != CEE_CALL)
8021                 supported_tail_call = FALSE;
8022
8023         /* Debugging support */
8024 #if 0
8025         if (supported_tail_call) {
8026                 if (!mono_debug_count ())
8027                         supported_tail_call = FALSE;
8028         }
8029 #endif
8030
8031         return supported_tail_call;
8032 }
8033
8034 /*
8035  * handle_ctor_call:
8036  *
8037  *   Handle calls made to ctors from NEWOBJ opcodes.
8038  */
8039 static void
8040 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
8041                                   MonoInst **sp, guint8 *ip, int *inline_costs)
8042 {
8043         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
8044
8045         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
8046                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
8047                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
8048                         mono_class_vtable (cfg->domain, cmethod->klass);
8049                         CHECK_TYPELOAD (cmethod->klass);
8050
8051                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
8052                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8053                 } else {
8054                         if (context_used) {
8055                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
8056                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8057                         } else {
8058                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8059
8060                                 CHECK_TYPELOAD (cmethod->klass);
8061                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8062                         }
8063                 }
8064         }
8065
8066         /* Avoid virtual calls to ctors if possible */
8067         if (mono_class_is_marshalbyref (cmethod->klass))
8068                 callvirt_this_arg = sp [0];
8069
8070         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8071                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
8072                 CHECK_CFG_EXCEPTION;
8073         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8074                            mono_method_check_inlining (cfg, cmethod) &&
8075                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
8076                 int costs;
8077
8078                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
8079                         cfg->real_offset += 5;
8080
8081                         *inline_costs += costs - 5;
8082                 } else {
8083                         INLINE_FAILURE ("inline failure");
8084                         // FIXME-VT: Clean this up
8085                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8086                                 GSHAREDVT_FAILURE(*ip);
8087                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
8088                 }
8089         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8090                 MonoInst *addr;
8091
8092                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
8093
8094                 if (cfg->llvm_only) {
8095                         // FIXME: Avoid initializing vtable_arg
8096                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8097                 } else {
8098                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
8099                 }
8100         } else if (context_used &&
8101                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8102                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
8103                 MonoInst *cmethod_addr;
8104
8105                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
8106
8107                 if (cfg->llvm_only) {
8108                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
8109                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8110                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8111                 } else {
8112                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8113                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8114
8115                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
8116                 }
8117         } else {
8118                 INLINE_FAILURE ("ctor call");
8119                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
8120                                                                                   callvirt_this_arg, NULL, vtable_arg);
8121         }
8122  exception_exit:
8123         return;
8124 }
8125
8126 static void
8127 emit_setret (MonoCompile *cfg, MonoInst *val)
8128 {
8129         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
8130         MonoInst *ins;
8131
8132         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8133                 MonoInst *ret_addr;
8134
8135                 if (!cfg->vret_addr) {
8136                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
8137                 } else {
8138                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8139
8140                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
8141                         ins->klass = mono_class_from_mono_type (ret_type);
8142                 }
8143         } else {
8144 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8145                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8146                         MonoInst *iargs [1];
8147                         MonoInst *conv;
8148
8149                         iargs [0] = val;
8150                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8151                         mono_arch_emit_setret (cfg, cfg->method, conv);
8152                 } else {
8153                         mono_arch_emit_setret (cfg, cfg->method, val);
8154                 }
8155 #else
8156                 mono_arch_emit_setret (cfg, cfg->method, val);
8157 #endif
8158         }
8159 }
8160
8161 /*
8162  * mono_method_to_ir:
8163  *
8164  * Translate the .net IL into linear IR.
8165  *
8166  * @start_bblock: if not NULL, the starting basic block, used during inlining.
8167  * @end_bblock: if not NULL, the ending basic block, used during inlining.
8168  * @return_var: if not NULL, the place where the return value is stored, used during inlining.   
8169  * @inline_args: if not NULL, contains the arguments to the inline call
8170  * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise.
8171  * @is_virtual_call: whether this method is being called as a result of a call to callvirt
8172  *
8173  * This method is used to turn ECMA IL into Mono's internal Linear IR
8174  * reprensetation.  It is used both for entire methods, as well as
8175  * inlining existing methods.  In the former case, the @start_bblock,
8176  * @end_bblock, @return_var, @inline_args are all set to NULL, and the
8177  * inline_offset is set to zero.
8178  * 
8179  * Returns: the inline cost, or -1 if there was an error processing this method.
8180  */
8181 int
8182 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
8183                    MonoInst *return_var, MonoInst **inline_args, 
8184                    guint inline_offset, gboolean is_virtual_call)
8185 {
8186         MonoError error;
8187         MonoInst *ins, **sp, **stack_start;
8188         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
8189         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
8190         MonoMethod *cmethod, *method_definition;
8191         MonoInst **arg_array;
8192         MonoMethodHeader *header;
8193         MonoImage *image;
8194         guint32 token, ins_flag;
8195         MonoClass *klass;
8196         MonoClass *constrained_class = NULL;
8197         unsigned char *ip, *end, *target, *err_pos;
8198         MonoMethodSignature *sig;
8199         MonoGenericContext *generic_context = NULL;
8200         MonoGenericContainer *generic_container = NULL;
8201         MonoType **param_types;
8202         int i, n, start_new_bblock, dreg;
8203         int num_calls = 0, inline_costs = 0;
8204         int breakpoint_id = 0;
8205         guint num_args;
8206         GSList *class_inits = NULL;
8207         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
8208         int context_used;
8209         gboolean init_locals, seq_points, skip_dead_blocks;
8210         gboolean sym_seq_points = FALSE;
8211         MonoDebugMethodInfo *minfo;
8212         MonoBitSet *seq_point_locs = NULL;
8213         MonoBitSet *seq_point_set_locs = NULL;
8214
8215         cfg->disable_inline = is_jit_optimizer_disabled (method);
8216
8217         /* serialization and xdomain stuff may need access to private fields and methods */
8218         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
8219         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
8220         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
8221         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
8222         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
8223         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
8224
8225         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
8226         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
8227         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
8228         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
8229         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
8230
8231         image = method->klass->image;
8232         header = mono_method_get_header_checked (method, &cfg->error);
8233         if (!header) {
8234                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
8235                 goto exception_exit;
8236         } else {
8237                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
8238         }
8239
8240         generic_container = mono_method_get_generic_container (method);
8241         sig = mono_method_signature (method);
8242         num_args = sig->hasthis + sig->param_count;
8243         ip = (unsigned char*)header->code;
8244         cfg->cil_start = ip;
8245         end = ip + header->code_size;
8246         cfg->stat_cil_code_size += header->code_size;
8247
8248         seq_points = cfg->gen_seq_points && cfg->method == method;
8249
8250         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8251                 /* We could hit a seq point before attaching to the JIT (#8338) */
8252                 seq_points = FALSE;
8253         }
8254
8255         if (cfg->gen_sdb_seq_points && cfg->method == method) {
8256                 minfo = mono_debug_lookup_method (method);
8257                 if (minfo) {
8258                         MonoSymSeqPoint *sps;
8259                         int i, n_il_offsets;
8260
8261                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
8262                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8263                         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);
8264                         sym_seq_points = TRUE;
8265                         for (i = 0; i < n_il_offsets; ++i) {
8266                                 if (sps [i].il_offset < header->code_size)
8267                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
8268                         }
8269                         g_free (sps);
8270                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
8271                         /* Methods without line number info like auto-generated property accessors */
8272                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8273                         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);
8274                         sym_seq_points = TRUE;
8275                 }
8276         }
8277
8278         /* 
8279          * Methods without init_locals set could cause asserts in various passes
8280          * (#497220). To work around this, we emit dummy initialization opcodes
8281          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
8282          * on some platforms.
8283          */
8284         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
8285                 init_locals = header->init_locals;
8286         else
8287                 init_locals = TRUE;
8288
8289         method_definition = method;
8290         while (method_definition->is_inflated) {
8291                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
8292                 method_definition = imethod->declaring;
8293         }
8294
8295         /* SkipVerification is not allowed if core-clr is enabled */
8296         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
8297                 dont_verify = TRUE;
8298                 dont_verify_stloc = TRUE;
8299         }
8300
8301         if (sig->is_inflated)
8302                 generic_context = mono_method_get_context (method);
8303         else if (generic_container)
8304                 generic_context = &generic_container->context;
8305         cfg->generic_context = generic_context;
8306
8307         if (!cfg->gshared)
8308                 g_assert (!sig->has_type_parameters);
8309
8310         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
8311                 g_assert (method->is_inflated);
8312                 g_assert (mono_method_get_context (method)->method_inst);
8313         }
8314         if (method->is_inflated && mono_method_get_context (method)->method_inst)
8315                 g_assert (sig->generic_param_count);
8316
8317         if (cfg->method == method) {
8318                 cfg->real_offset = 0;
8319         } else {
8320                 cfg->real_offset = inline_offset;
8321         }
8322
8323         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
8324         cfg->cil_offset_to_bb_len = header->code_size;
8325
8326         cfg->current_method = method;
8327
8328         if (cfg->verbose_level > 2)
8329                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
8330
8331         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
8332         if (sig->hasthis)
8333                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
8334         for (n = 0; n < sig->param_count; ++n)
8335                 param_types [n + sig->hasthis] = sig->params [n];
8336         cfg->arg_types = param_types;
8337
8338         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
8339         if (cfg->method == method) {
8340
8341                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
8342                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
8343
8344                 /* ENTRY BLOCK */
8345                 NEW_BBLOCK (cfg, start_bblock);
8346                 cfg->bb_entry = start_bblock;
8347                 start_bblock->cil_code = NULL;
8348                 start_bblock->cil_length = 0;
8349
8350                 /* EXIT BLOCK */
8351                 NEW_BBLOCK (cfg, end_bblock);
8352                 cfg->bb_exit = end_bblock;
8353                 end_bblock->cil_code = NULL;
8354                 end_bblock->cil_length = 0;
8355                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8356                 g_assert (cfg->num_bblocks == 2);
8357
8358                 arg_array = cfg->args;
8359
8360                 if (header->num_clauses) {
8361                         cfg->spvars = g_hash_table_new (NULL, NULL);
8362                         cfg->exvars = g_hash_table_new (NULL, NULL);
8363                 }
8364                 /* handle exception clauses */
8365                 for (i = 0; i < header->num_clauses; ++i) {
8366                         MonoBasicBlock *try_bb;
8367                         MonoExceptionClause *clause = &header->clauses [i];
8368                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8369
8370                         try_bb->real_offset = clause->try_offset;
8371                         try_bb->try_start = TRUE;
8372                         try_bb->region = ((i + 1) << 8) | clause->flags;
8373                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8374                         tblock->real_offset = clause->handler_offset;
8375                         tblock->flags |= BB_EXCEPTION_HANDLER;
8376
8377                         /*
8378                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8379                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8380                          */
8381                         if (COMPILE_LLVM (cfg))
8382                                 link_bblock (cfg, try_bb, tblock);
8383
8384                         if (*(ip + clause->handler_offset) == CEE_POP)
8385                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8386
8387                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8388                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8389                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8390                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8391                                 MONO_ADD_INS (tblock, ins);
8392
8393                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8394                                         /* finally clauses already have a seq point */
8395                                         /* seq points for filter clauses are emitted below */
8396                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8397                                         MONO_ADD_INS (tblock, ins);
8398                                 }
8399
8400                                 /* todo: is a fault block unsafe to optimize? */
8401                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8402                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8403                         }
8404
8405                         /*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);
8406                           while (p < end) {
8407                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8408                           }*/
8409                         /* catch and filter blocks get the exception object on the stack */
8410                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8411                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8412
8413                                 /* mostly like handle_stack_args (), but just sets the input args */
8414                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8415                                 tblock->in_scount = 1;
8416                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8417                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8418
8419                                 cfg->cbb = tblock;
8420
8421 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8422                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8423                                 if (!cfg->compile_llvm) {
8424                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8425                                         ins->dreg = tblock->in_stack [0]->dreg;
8426                                         MONO_ADD_INS (tblock, ins);
8427                                 }
8428 #else
8429                                 MonoInst *dummy_use;
8430
8431                                 /* 
8432                                  * Add a dummy use for the exvar so its liveness info will be
8433                                  * correct.
8434                                  */
8435                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8436 #endif
8437
8438                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8439                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8440                                         MONO_ADD_INS (tblock, ins);
8441                                 }
8442                                 
8443                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8444                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8445                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8446                                         tblock->real_offset = clause->data.filter_offset;
8447                                         tblock->in_scount = 1;
8448                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8449                                         /* The filter block shares the exvar with the handler block */
8450                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8451                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8452                                         MONO_ADD_INS (tblock, ins);
8453                                 }
8454                         }
8455
8456                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8457                                         clause->data.catch_class &&
8458                                         cfg->gshared &&
8459                                         mono_class_check_context_used (clause->data.catch_class)) {
8460                                 /*
8461                                  * In shared generic code with catch
8462                                  * clauses containing type variables
8463                                  * the exception handling code has to
8464                                  * be able to get to the rgctx.
8465                                  * Therefore we have to make sure that
8466                                  * the vtable/mrgctx argument (for
8467                                  * static or generic methods) or the
8468                                  * "this" argument (for non-static
8469                                  * methods) are live.
8470                                  */
8471                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8472                                                 mini_method_get_context (method)->method_inst ||
8473                                                 method->klass->valuetype) {
8474                                         mono_get_vtable_var (cfg);
8475                                 } else {
8476                                         MonoInst *dummy_use;
8477
8478                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8479                                 }
8480                         }
8481                 }
8482         } else {
8483                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8484                 cfg->cbb = start_bblock;
8485                 cfg->args = arg_array;
8486                 mono_save_args (cfg, sig, inline_args);
8487         }
8488
8489         /* FIRST CODE BLOCK */
8490         NEW_BBLOCK (cfg, tblock);
8491         tblock->cil_code = ip;
8492         cfg->cbb = tblock;
8493         cfg->ip = ip;
8494
8495         ADD_BBLOCK (cfg, tblock);
8496
8497         if (cfg->method == method) {
8498                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8499                 if (breakpoint_id) {
8500                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8501                         MONO_ADD_INS (cfg->cbb, ins);
8502                 }
8503         }
8504
8505         /* we use a separate basic block for the initialization code */
8506         NEW_BBLOCK (cfg, init_localsbb);
8507         if (cfg->method == method)
8508                 cfg->bb_init = init_localsbb;
8509         init_localsbb->real_offset = cfg->real_offset;
8510         start_bblock->next_bb = init_localsbb;
8511         init_localsbb->next_bb = cfg->cbb;
8512         link_bblock (cfg, start_bblock, init_localsbb);
8513         link_bblock (cfg, init_localsbb, cfg->cbb);
8514                 
8515         cfg->cbb = init_localsbb;
8516
8517         if (cfg->gsharedvt && cfg->method == method) {
8518                 MonoGSharedVtMethodInfo *info;
8519                 MonoInst *var, *locals_var;
8520                 int dreg;
8521
8522                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8523                 info->method = cfg->method;
8524                 info->count_entries = 16;
8525                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8526                 cfg->gsharedvt_info = info;
8527
8528                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8529                 /* prevent it from being register allocated */
8530                 //var->flags |= MONO_INST_VOLATILE;
8531                 cfg->gsharedvt_info_var = var;
8532
8533                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8534                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8535
8536                 /* Allocate locals */
8537                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8538                 /* prevent it from being register allocated */
8539                 //locals_var->flags |= MONO_INST_VOLATILE;
8540                 cfg->gsharedvt_locals_var = locals_var;
8541
8542                 dreg = alloc_ireg (cfg);
8543                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8544
8545                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8546                 ins->dreg = locals_var->dreg;
8547                 ins->sreg1 = dreg;
8548                 MONO_ADD_INS (cfg->cbb, ins);
8549                 cfg->gsharedvt_locals_var_ins = ins;
8550                 
8551                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8552                 /*
8553                 if (init_locals)
8554                         ins->flags |= MONO_INST_INIT;
8555                 */
8556         }
8557
8558         if (mono_security_core_clr_enabled ()) {
8559                 /* check if this is native code, e.g. an icall or a p/invoke */
8560                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8561                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8562                         if (wrapped) {
8563                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8564                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8565
8566                                 /* if this ia a native call then it can only be JITted from platform code */
8567                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8568                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8569                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8570                                                         mono_get_exception_method_access ();
8571                                                 emit_throw_exception (cfg, ex);
8572                                         }
8573                                 }
8574                         }
8575                 }
8576         }
8577
8578         CHECK_CFG_EXCEPTION;
8579
8580         if (header->code_size == 0)
8581                 UNVERIFIED;
8582
8583         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8584                 ip = err_pos;
8585                 UNVERIFIED;
8586         }
8587
8588         if (cfg->method == method)
8589                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8590
8591         for (n = 0; n < header->num_locals; ++n) {
8592                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8593                         UNVERIFIED;
8594         }
8595         class_inits = NULL;
8596
8597         /* We force the vtable variable here for all shared methods
8598            for the possibility that they might show up in a stack
8599            trace where their exact instantiation is needed. */
8600         if (cfg->gshared && method == cfg->method) {
8601                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8602                                 mini_method_get_context (method)->method_inst ||
8603                                 method->klass->valuetype) {
8604                         mono_get_vtable_var (cfg);
8605                 } else {
8606                         /* FIXME: Is there a better way to do this?
8607                            We need the variable live for the duration
8608                            of the whole method. */
8609                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8610                 }
8611         }
8612
8613         /* add a check for this != NULL to inlined methods */
8614         if (is_virtual_call) {
8615                 MonoInst *arg_ins;
8616
8617                 NEW_ARGLOAD (cfg, arg_ins, 0);
8618                 MONO_ADD_INS (cfg->cbb, arg_ins);
8619                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8620         }
8621
8622         skip_dead_blocks = !dont_verify;
8623         if (skip_dead_blocks) {
8624                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
8625                 CHECK_CFG_ERROR;
8626                 g_assert (bb);
8627         }
8628
8629         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8630         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8631
8632         ins_flag = 0;
8633         start_new_bblock = 0;
8634         while (ip < end) {
8635                 if (cfg->method == method)
8636                         cfg->real_offset = ip - header->code;
8637                 else
8638                         cfg->real_offset = inline_offset;
8639                 cfg->ip = ip;
8640
8641                 context_used = 0;
8642
8643                 if (start_new_bblock) {
8644                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8645                         if (start_new_bblock == 2) {
8646                                 g_assert (ip == tblock->cil_code);
8647                         } else {
8648                                 GET_BBLOCK (cfg, tblock, ip);
8649                         }
8650                         cfg->cbb->next_bb = tblock;
8651                         cfg->cbb = tblock;
8652                         start_new_bblock = 0;
8653                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8654                                 if (cfg->verbose_level > 3)
8655                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8656                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8657                                 *sp++ = ins;
8658                         }
8659                         if (class_inits)
8660                                 g_slist_free (class_inits);
8661                         class_inits = NULL;
8662                 } else {
8663                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8664                                 link_bblock (cfg, cfg->cbb, tblock);
8665                                 if (sp != stack_start) {
8666                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8667                                         sp = stack_start;
8668                                         CHECK_UNVERIFIABLE (cfg);
8669                                 }
8670                                 cfg->cbb->next_bb = tblock;
8671                                 cfg->cbb = tblock;
8672                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8673                                         if (cfg->verbose_level > 3)
8674                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8675                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8676                                         *sp++ = ins;
8677                                 }
8678                                 g_slist_free (class_inits);
8679                                 class_inits = NULL;
8680                         }
8681                 }
8682
8683                 if (skip_dead_blocks) {
8684                         int ip_offset = ip - header->code;
8685
8686                         if (ip_offset == bb->end)
8687                                 bb = bb->next;
8688
8689                         if (bb->dead) {
8690                                 int op_size = mono_opcode_size (ip, end);
8691                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8692
8693                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8694
8695                                 if (ip_offset + op_size == bb->end) {
8696                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8697                                         MONO_ADD_INS (cfg->cbb, ins);
8698                                         start_new_bblock = 1;
8699                                 }
8700
8701                                 ip += op_size;
8702                                 continue;
8703                         }
8704                 }
8705                 /*
8706                  * Sequence points are points where the debugger can place a breakpoint.
8707                  * Currently, we generate these automatically at points where the IL
8708                  * stack is empty.
8709                  */
8710                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8711                         /*
8712                          * Make methods interruptable at the beginning, and at the targets of
8713                          * backward branches.
8714                          * Also, do this at the start of every bblock in methods with clauses too,
8715                          * to be able to handle instructions with inprecise control flow like
8716                          * throw/endfinally.
8717                          * Backward branches are handled at the end of method-to-ir ().
8718                          */
8719                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8720                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8721
8722                         /* Avoid sequence points on empty IL like .volatile */
8723                         // FIXME: Enable this
8724                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8725                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8726                         if ((sp != stack_start) && !sym_seq_point)
8727                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8728                         MONO_ADD_INS (cfg->cbb, ins);
8729
8730                         if (sym_seq_points)
8731                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8732                 }
8733
8734                 cfg->cbb->real_offset = cfg->real_offset;
8735
8736                 if ((cfg->method == method) && cfg->coverage_info) {
8737                         guint32 cil_offset = ip - header->code;
8738                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8739
8740                         /* TODO: Use an increment here */
8741 #if defined(TARGET_X86)
8742                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8743                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8744                         ins->inst_imm = 1;
8745                         MONO_ADD_INS (cfg->cbb, ins);
8746 #else
8747                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8748                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8749 #endif
8750                 }
8751
8752                 if (cfg->verbose_level > 3)
8753                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8754
8755                 switch (*ip) {
8756                 case CEE_NOP:
8757                         if (seq_points && !sym_seq_points && sp != stack_start) {
8758                                 /*
8759                                  * The C# compiler uses these nops to notify the JIT that it should
8760                                  * insert seq points.
8761                                  */
8762                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8763                                 MONO_ADD_INS (cfg->cbb, ins);
8764                         }
8765                         if (cfg->keep_cil_nops)
8766                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8767                         else
8768                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8769                         ip++;
8770                         MONO_ADD_INS (cfg->cbb, ins);
8771                         break;
8772                 case CEE_BREAK:
8773                         if (should_insert_brekpoint (cfg->method)) {
8774                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8775                         } else {
8776                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8777                         }
8778                         ip++;
8779                         MONO_ADD_INS (cfg->cbb, ins);
8780                         break;
8781                 case CEE_LDARG_0:
8782                 case CEE_LDARG_1:
8783                 case CEE_LDARG_2:
8784                 case CEE_LDARG_3:
8785                         CHECK_STACK_OVF (1);
8786                         n = (*ip)-CEE_LDARG_0;
8787                         CHECK_ARG (n);
8788                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8789                         ip++;
8790                         *sp++ = ins;
8791                         break;
8792                 case CEE_LDLOC_0:
8793                 case CEE_LDLOC_1:
8794                 case CEE_LDLOC_2:
8795                 case CEE_LDLOC_3:
8796                         CHECK_STACK_OVF (1);
8797                         n = (*ip)-CEE_LDLOC_0;
8798                         CHECK_LOCAL (n);
8799                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8800                         ip++;
8801                         *sp++ = ins;
8802                         break;
8803                 case CEE_STLOC_0:
8804                 case CEE_STLOC_1:
8805                 case CEE_STLOC_2:
8806                 case CEE_STLOC_3: {
8807                         CHECK_STACK (1);
8808                         n = (*ip)-CEE_STLOC_0;
8809                         CHECK_LOCAL (n);
8810                         --sp;
8811                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8812                                 UNVERIFIED;
8813                         emit_stloc_ir (cfg, sp, header, n);
8814                         ++ip;
8815                         inline_costs += 1;
8816                         break;
8817                         }
8818                 case CEE_LDARG_S:
8819                         CHECK_OPSIZE (2);
8820                         CHECK_STACK_OVF (1);
8821                         n = ip [1];
8822                         CHECK_ARG (n);
8823                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8824                         *sp++ = ins;
8825                         ip += 2;
8826                         break;
8827                 case CEE_LDARGA_S:
8828                         CHECK_OPSIZE (2);
8829                         CHECK_STACK_OVF (1);
8830                         n = ip [1];
8831                         CHECK_ARG (n);
8832                         NEW_ARGLOADA (cfg, ins, n);
8833                         MONO_ADD_INS (cfg->cbb, ins);
8834                         *sp++ = ins;
8835                         ip += 2;
8836                         break;
8837                 case CEE_STARG_S:
8838                         CHECK_OPSIZE (2);
8839                         CHECK_STACK (1);
8840                         --sp;
8841                         n = ip [1];
8842                         CHECK_ARG (n);
8843                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8844                                 UNVERIFIED;
8845                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8846                         ip += 2;
8847                         break;
8848                 case CEE_LDLOC_S:
8849                         CHECK_OPSIZE (2);
8850                         CHECK_STACK_OVF (1);
8851                         n = ip [1];
8852                         CHECK_LOCAL (n);
8853                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8854                         *sp++ = ins;
8855                         ip += 2;
8856                         break;
8857                 case CEE_LDLOCA_S: {
8858                         unsigned char *tmp_ip;
8859                         CHECK_OPSIZE (2);
8860                         CHECK_STACK_OVF (1);
8861                         CHECK_LOCAL (ip [1]);
8862
8863                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8864                                 ip = tmp_ip;
8865                                 inline_costs += 1;
8866                                 break;
8867                         }
8868
8869                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8870                         *sp++ = ins;
8871                         ip += 2;
8872                         break;
8873                 }
8874                 case CEE_STLOC_S:
8875                         CHECK_OPSIZE (2);
8876                         CHECK_STACK (1);
8877                         --sp;
8878                         CHECK_LOCAL (ip [1]);
8879                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8880                                 UNVERIFIED;
8881                         emit_stloc_ir (cfg, sp, header, ip [1]);
8882                         ip += 2;
8883                         inline_costs += 1;
8884                         break;
8885                 case CEE_LDNULL:
8886                         CHECK_STACK_OVF (1);
8887                         EMIT_NEW_PCONST (cfg, ins, NULL);
8888                         ins->type = STACK_OBJ;
8889                         ++ip;
8890                         *sp++ = ins;
8891                         break;
8892                 case CEE_LDC_I4_M1:
8893                         CHECK_STACK_OVF (1);
8894                         EMIT_NEW_ICONST (cfg, ins, -1);
8895                         ++ip;
8896                         *sp++ = ins;
8897                         break;
8898                 case CEE_LDC_I4_0:
8899                 case CEE_LDC_I4_1:
8900                 case CEE_LDC_I4_2:
8901                 case CEE_LDC_I4_3:
8902                 case CEE_LDC_I4_4:
8903                 case CEE_LDC_I4_5:
8904                 case CEE_LDC_I4_6:
8905                 case CEE_LDC_I4_7:
8906                 case CEE_LDC_I4_8:
8907                         CHECK_STACK_OVF (1);
8908                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8909                         ++ip;
8910                         *sp++ = ins;
8911                         break;
8912                 case CEE_LDC_I4_S:
8913                         CHECK_OPSIZE (2);
8914                         CHECK_STACK_OVF (1);
8915                         ++ip;
8916                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8917                         ++ip;
8918                         *sp++ = ins;
8919                         break;
8920                 case CEE_LDC_I4:
8921                         CHECK_OPSIZE (5);
8922                         CHECK_STACK_OVF (1);
8923                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8924                         ip += 5;
8925                         *sp++ = ins;
8926                         break;
8927                 case CEE_LDC_I8:
8928                         CHECK_OPSIZE (9);
8929                         CHECK_STACK_OVF (1);
8930                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8931                         ins->type = STACK_I8;
8932                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8933                         ++ip;
8934                         ins->inst_l = (gint64)read64 (ip);
8935                         MONO_ADD_INS (cfg->cbb, ins);
8936                         ip += 8;
8937                         *sp++ = ins;
8938                         break;
8939                 case CEE_LDC_R4: {
8940                         float *f;
8941                         gboolean use_aotconst = FALSE;
8942
8943 #ifdef TARGET_POWERPC
8944                         /* FIXME: Clean this up */
8945                         if (cfg->compile_aot)
8946                                 use_aotconst = TRUE;
8947 #endif
8948
8949                         /* FIXME: we should really allocate this only late in the compilation process */
8950                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8951                         CHECK_OPSIZE (5);
8952                         CHECK_STACK_OVF (1);
8953
8954                         if (use_aotconst) {
8955                                 MonoInst *cons;
8956                                 int dreg;
8957
8958                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8959
8960                                 dreg = alloc_freg (cfg);
8961                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8962                                 ins->type = cfg->r4_stack_type;
8963                         } else {
8964                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8965                                 ins->type = cfg->r4_stack_type;
8966                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8967                                 ins->inst_p0 = f;
8968                                 MONO_ADD_INS (cfg->cbb, ins);
8969                         }
8970                         ++ip;
8971                         readr4 (ip, f);
8972                         ip += 4;
8973                         *sp++ = ins;                    
8974                         break;
8975                 }
8976                 case CEE_LDC_R8: {
8977                         double *d;
8978                         gboolean use_aotconst = FALSE;
8979
8980 #ifdef TARGET_POWERPC
8981                         /* FIXME: Clean this up */
8982                         if (cfg->compile_aot)
8983                                 use_aotconst = TRUE;
8984 #endif
8985
8986                         /* FIXME: we should really allocate this only late in the compilation process */
8987                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8988                         CHECK_OPSIZE (9);
8989                         CHECK_STACK_OVF (1);
8990
8991                         if (use_aotconst) {
8992                                 MonoInst *cons;
8993                                 int dreg;
8994
8995                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8996
8997                                 dreg = alloc_freg (cfg);
8998                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8999                                 ins->type = STACK_R8;
9000                         } else {
9001                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
9002                                 ins->type = STACK_R8;
9003                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
9004                                 ins->inst_p0 = d;
9005                                 MONO_ADD_INS (cfg->cbb, ins);
9006                         }
9007                         ++ip;
9008                         readr8 (ip, d);
9009                         ip += 8;
9010                         *sp++ = ins;
9011                         break;
9012                 }
9013                 case CEE_DUP: {
9014                         MonoInst *temp, *store;
9015                         CHECK_STACK (1);
9016                         CHECK_STACK_OVF (1);
9017                         sp--;
9018                         ins = *sp;
9019
9020                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
9021                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
9022
9023                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
9024                         *sp++ = ins;
9025
9026                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
9027                         *sp++ = ins;
9028
9029                         ++ip;
9030                         inline_costs += 2;
9031                         break;
9032                 }
9033                 case CEE_POP:
9034                         CHECK_STACK (1);
9035                         ip++;
9036                         --sp;
9037
9038 #ifdef TARGET_X86
9039                         if (sp [0]->type == STACK_R8)
9040                                 /* we need to pop the value from the x86 FP stack */
9041                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
9042 #endif
9043                         break;
9044                 case CEE_JMP: {
9045                         MonoCallInst *call;
9046                         MonoMethodSignature *fsig;
9047                         int i, n;
9048
9049                         INLINE_FAILURE ("jmp");
9050                         GSHAREDVT_FAILURE (*ip);
9051
9052                         CHECK_OPSIZE (5);
9053                         if (stack_start != sp)
9054                                 UNVERIFIED;
9055                         token = read32 (ip + 1);
9056                         /* FIXME: check the signature matches */
9057                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9058                         CHECK_CFG_ERROR;
9059  
9060                         if (cfg->gshared && mono_method_check_context_used (cmethod))
9061                                 GENERIC_SHARING_FAILURE (CEE_JMP);
9062
9063                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9064
9065                         fsig = mono_method_signature (cmethod);
9066                         n = fsig->param_count + fsig->hasthis;
9067                         if (cfg->llvm_only) {
9068                                 MonoInst **args;
9069
9070                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9071                                 for (i = 0; i < n; ++i)
9072                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
9073                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
9074                                 /*
9075                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
9076                                  * have to emit a normal return since llvm expects it.
9077                                  */
9078                                 if (cfg->ret)
9079                                         emit_setret (cfg, ins);
9080                                 MONO_INST_NEW (cfg, ins, OP_BR);
9081                                 ins->inst_target_bb = end_bblock;
9082                                 MONO_ADD_INS (cfg->cbb, ins);
9083                                 link_bblock (cfg, cfg->cbb, end_bblock);
9084                                 ip += 5;
9085                                 break;
9086                         } else if (cfg->backend->have_op_tail_call) {
9087                                 /* Handle tail calls similarly to calls */
9088                                 DISABLE_AOT (cfg);
9089
9090                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
9091                                 call->method = cmethod;
9092                                 call->tail_call = TRUE;
9093                                 call->signature = mono_method_signature (cmethod);
9094                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9095                                 call->inst.inst_p0 = cmethod;
9096                                 for (i = 0; i < n; ++i)
9097                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
9098
9099                                 if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
9100                                         call->vret_var = cfg->vret_addr;
9101
9102                                 mono_arch_emit_call (cfg, call);
9103                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
9104                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
9105                         } else {
9106                                 for (i = 0; i < num_args; ++i)
9107                                         /* Prevent arguments from being optimized away */
9108                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
9109
9110                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9111                                 ins = (MonoInst*)call;
9112                                 ins->inst_p0 = cmethod;
9113                                 MONO_ADD_INS (cfg->cbb, ins);
9114                         }
9115
9116                         ip += 5;
9117                         start_new_bblock = 1;
9118                         break;
9119                 }
9120                 case CEE_CALLI: {
9121                         MonoInst *addr;
9122                         MonoMethodSignature *fsig;
9123
9124                         CHECK_OPSIZE (5);
9125                         token = read32 (ip + 1);
9126
9127                         ins = NULL;
9128
9129                         //GSHAREDVT_FAILURE (*ip);
9130                         cmethod = NULL;
9131                         CHECK_STACK (1);
9132                         --sp;
9133                         addr = *sp;
9134                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
9135                         CHECK_CFG_ERROR;
9136
9137                         if (method->dynamic && fsig->pinvoke) {
9138                                 MonoInst *args [3];
9139
9140                                 /*
9141                                  * This is a call through a function pointer using a pinvoke
9142                                  * signature. Have to create a wrapper and call that instead.
9143                                  * FIXME: This is very slow, need to create a wrapper at JIT time
9144                                  * instead based on the signature.
9145                                  */
9146                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
9147                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
9148                                 args [2] = addr;
9149                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
9150                         }
9151
9152                         n = fsig->param_count + fsig->hasthis;
9153
9154                         CHECK_STACK (n);
9155
9156                         //g_assert (!virtual_ || fsig->hasthis);
9157
9158                         sp -= n;
9159
9160                         inline_costs += 10 * num_calls++;
9161
9162                         /*
9163                          * Making generic calls out of gsharedvt methods.
9164                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9165                          * patching gshared method addresses into a gsharedvt method.
9166                          */
9167                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
9168                                 /*
9169                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9170                                  */
9171                                 MonoInst *callee = addr;
9172
9173                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9174                                         /* Not tested */
9175                                         GSHAREDVT_FAILURE (*ip);
9176
9177                                 if (cfg->llvm_only)
9178                                         // FIXME:
9179                                         GSHAREDVT_FAILURE (*ip);
9180
9181                                 addr = emit_get_rgctx_sig (cfg, context_used,
9182                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9183                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9184                                 goto calli_end;
9185                         }
9186
9187                         /* Prevent inlining of methods with indirect calls */
9188                         INLINE_FAILURE ("indirect call");
9189
9190                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9191                                 MonoJumpInfoType info_type;
9192                                 gpointer info_data;
9193
9194                                 /*
9195                                  * Instead of emitting an indirect call, emit a direct call
9196                                  * with the contents of the aotconst as the patch info.
9197                                  */
9198                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9199                                         info_type = (MonoJumpInfoType)addr->inst_c1;
9200                                         info_data = addr->inst_p0;
9201                                 } else {
9202                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
9203                                         info_data = addr->inst_right->inst_left;
9204                                 }
9205
9206                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
9207                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
9208                                         NULLIFY_INS (addr);
9209                                         goto calli_end;
9210                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9211                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9212                                         NULLIFY_INS (addr);
9213                                         goto calli_end;
9214                                 }
9215                         }
9216                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9217
9218                         calli_end:
9219
9220                         /* End of call, INS should contain the result of the call, if any */
9221
9222                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9223                                 g_assert (ins);
9224                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9225                         }
9226
9227                         CHECK_CFG_EXCEPTION;
9228
9229                         ip += 5;
9230                         ins_flag = 0;
9231                         constrained_class = NULL;
9232                         break;
9233                 }
9234                 case CEE_CALL:
9235                 case CEE_CALLVIRT: {
9236                         MonoInst *addr = NULL;
9237                         MonoMethodSignature *fsig = NULL;
9238                         int array_rank = 0;
9239                         int virtual_ = *ip == CEE_CALLVIRT;
9240                         gboolean pass_imt_from_rgctx = FALSE;
9241                         MonoInst *imt_arg = NULL;
9242                         MonoInst *keep_this_alive = NULL;
9243                         gboolean pass_vtable = FALSE;
9244                         gboolean pass_mrgctx = FALSE;
9245                         MonoInst *vtable_arg = NULL;
9246                         gboolean check_this = FALSE;
9247                         gboolean supported_tail_call = FALSE;
9248                         gboolean tail_call = FALSE;
9249                         gboolean need_seq_point = FALSE;
9250                         guint32 call_opcode = *ip;
9251                         gboolean emit_widen = TRUE;
9252                         gboolean push_res = TRUE;
9253                         gboolean skip_ret = FALSE;
9254                         gboolean delegate_invoke = FALSE;
9255                         gboolean direct_icall = FALSE;
9256                         gboolean constrained_partial_call = FALSE;
9257                         MonoMethod *cil_method;
9258
9259                         CHECK_OPSIZE (5);
9260                         token = read32 (ip + 1);
9261
9262                         ins = NULL;
9263
9264                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9265                         CHECK_CFG_ERROR;
9266
9267                         cil_method = cmethod;
9268                                 
9269                         if (constrained_class) {
9270                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9271                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9272                                                 g_assert (!cmethod->klass->valuetype);
9273                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9274                                                         constrained_partial_call = TRUE;
9275                                         }
9276                                 }
9277
9278                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9279                                         if (cfg->verbose_level > 2)
9280                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9281                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9282                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9283                                                   cfg->gshared)) {
9284                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9285                                                 CHECK_CFG_ERROR;
9286                                         }
9287                                 } else {
9288                                         if (cfg->verbose_level > 2)
9289                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9290
9291                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9292                                                 /* 
9293                                                  * This is needed since get_method_constrained can't find 
9294                                                  * the method in klass representing a type var.
9295                                                  * The type var is guaranteed to be a reference type in this
9296                                                  * case.
9297                                                  */
9298                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9299                                                         g_assert (!cmethod->klass->valuetype);
9300                                         } else {
9301                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9302                                                 CHECK_CFG_ERROR;
9303                                         }
9304                                 }
9305                         }
9306                                         
9307                         if (!dont_verify && !cfg->skip_visibility) {
9308                                 MonoMethod *target_method = cil_method;
9309                                 if (method->is_inflated) {
9310                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9311                                         CHECK_CFG_ERROR;
9312                                 }
9313                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9314                                         !mono_method_can_access_method (method, cil_method))
9315                                         emit_method_access_failure (cfg, method, cil_method);
9316                         }
9317
9318                         if (mono_security_core_clr_enabled ())
9319                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9320
9321                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9322                                 /* MS.NET seems to silently convert this to a callvirt */
9323                                 virtual_ = 1;
9324
9325                         {
9326                                 /*
9327                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9328                                  * converts to a callvirt.
9329                                  *
9330                                  * tests/bug-515884.il is an example of this behavior
9331                                  */
9332                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9333                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9334                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9335                                         virtual_ = 1;
9336                         }
9337
9338                         if (!cmethod->klass->inited)
9339                                 if (!mono_class_init (cmethod->klass))
9340                                         TYPE_LOAD_ERROR (cmethod->klass);
9341
9342                         fsig = mono_method_signature (cmethod);
9343                         if (!fsig)
9344                                 LOAD_ERROR;
9345                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9346                                 mini_class_is_system_array (cmethod->klass)) {
9347                                 array_rank = cmethod->klass->rank;
9348                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9349                                 direct_icall = TRUE;
9350                         } else if (fsig->pinvoke) {
9351                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9352                                 fsig = mono_method_signature (wrapper);
9353                         } else if (constrained_class) {
9354                         } else {
9355                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9356                                 CHECK_CFG_ERROR;
9357                         }
9358
9359                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
9360                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9361
9362                         /* See code below */
9363                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9364                                 MonoBasicBlock *tbb;
9365
9366                                 GET_BBLOCK (cfg, tbb, ip + 5);
9367                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9368                                         /*
9369                                          * We want to extend the try block to cover the call, but we can't do it if the
9370                                          * call is made directly since its followed by an exception check.
9371                                          */
9372                                         direct_icall = FALSE;
9373                                 }
9374                         }
9375
9376                         mono_save_token_info (cfg, image, token, cil_method);
9377
9378                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9379                                 need_seq_point = TRUE;
9380
9381                         /* Don't support calls made using type arguments for now */
9382                         /*
9383                           if (cfg->gsharedvt) {
9384                           if (mini_is_gsharedvt_signature (fsig))
9385                           GSHAREDVT_FAILURE (*ip);
9386                           }
9387                         */
9388
9389                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9390                                 g_assert_not_reached ();
9391
9392                         n = fsig->param_count + fsig->hasthis;
9393
9394                         if (!cfg->gshared && mono_class_is_gtd (cmethod->klass))
9395                                 UNVERIFIED;
9396
9397                         if (!cfg->gshared)
9398                                 g_assert (!mono_method_check_context_used (cmethod));
9399
9400                         CHECK_STACK (n);
9401
9402                         //g_assert (!virtual_ || fsig->hasthis);
9403
9404                         sp -= n;
9405
9406                         /*
9407                          * We have the `constrained.' prefix opcode.
9408                          */
9409                         if (constrained_class) {
9410                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9411                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9412                                                 /* The 'Own method' case below */
9413                                         } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) {
9414                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9415                                         } else {
9416                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9417                                                 CHECK_CFG_EXCEPTION;
9418                                                 g_assert (ins);
9419                                                 goto call_end;
9420                                         }
9421                                 }
9422
9423                                 if (constrained_partial_call) {
9424                                         gboolean need_box = TRUE;
9425
9426                                         /*
9427                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9428                                          * called method is not known at compile time either. The called method could end up being
9429                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9430                                          * to box the receiver.
9431                                          * A simple solution would be to box always and make a normal virtual call, but that would
9432                                          * be bad performance wise.
9433                                          */
9434                                         if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) {
9435                                                 /*
9436                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9437                                                  */
9438                                                 need_box = FALSE;
9439                                         }
9440
9441                                         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)) {
9442                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9443                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9444                                                 ins->klass = constrained_class;
9445                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9446                                                 CHECK_CFG_EXCEPTION;
9447                                         } else if (need_box) {
9448                                                 MonoInst *box_type;
9449                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9450                                                 MonoInst *nonbox_call;
9451
9452                                                 /*
9453                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9454                                                  * if needed.
9455                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9456                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9457                                                  */
9458                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9459
9460                                                 NEW_BBLOCK (cfg, is_ref_bb);
9461                                                 NEW_BBLOCK (cfg, end_bb);
9462
9463                                                 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);
9464                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9465                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9466
9467                                                 /* Non-ref case */
9468                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9469
9470                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9471
9472                                                 /* Ref case */
9473                                                 MONO_START_BB (cfg, is_ref_bb);
9474                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9475                                                 ins->klass = constrained_class;
9476                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9477                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9478
9479                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9480
9481                                                 MONO_START_BB (cfg, end_bb);
9482                                                 cfg->cbb = end_bb;
9483
9484                                                 nonbox_call->dreg = ins->dreg;
9485                                                 goto call_end;
9486                                         } else {
9487                                                 g_assert (mono_class_is_interface (cmethod->klass));
9488                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9489                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9490                                                 goto call_end;
9491                                         }
9492                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9493                                         /*
9494                                          * The type parameter is instantiated as a valuetype,
9495                                          * but that type doesn't override the method we're
9496                                          * calling, so we need to box `this'.
9497                                          */
9498                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9499                                         ins->klass = constrained_class;
9500                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9501                                         CHECK_CFG_EXCEPTION;
9502                                 } else if (!constrained_class->valuetype) {
9503                                         int dreg = alloc_ireg_ref (cfg);
9504
9505                                         /*
9506                                          * The type parameter is instantiated as a reference
9507                                          * type.  We have a managed pointer on the stack, so
9508                                          * we need to dereference it here.
9509                                          */
9510                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9511                                         ins->type = STACK_OBJ;
9512                                         sp [0] = ins;
9513                                 } else {
9514                                         if (cmethod->klass->valuetype) {
9515                                                 /* Own method */
9516                                         } else {
9517                                                 /* Interface method */
9518                                                 int ioffset, slot;
9519
9520                                                 mono_class_setup_vtable (constrained_class);
9521                                                 CHECK_TYPELOAD (constrained_class);
9522                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9523                                                 if (ioffset == -1)
9524                                                         TYPE_LOAD_ERROR (constrained_class);
9525                                                 slot = mono_method_get_vtable_slot (cmethod);
9526                                                 if (slot == -1)
9527                                                         TYPE_LOAD_ERROR (cmethod->klass);
9528                                                 cmethod = constrained_class->vtable [ioffset + slot];
9529
9530                                                 if (cmethod->klass == mono_defaults.enum_class) {
9531                                                         /* Enum implements some interfaces, so treat this as the first case */
9532                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9533                                                         ins->klass = constrained_class;
9534                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9535                                                         CHECK_CFG_EXCEPTION;
9536                                                 }
9537                                         }
9538                                         virtual_ = 0;
9539                                 }
9540                                 constrained_class = NULL;
9541                         }
9542
9543                         if (check_call_signature (cfg, fsig, sp))
9544                                 UNVERIFIED;
9545
9546                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9547                                 delegate_invoke = TRUE;
9548
9549                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9550                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9551                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9552                                         emit_widen = FALSE;
9553                                 }
9554
9555                                 goto call_end;
9556                         }
9557
9558                         /* 
9559                          * If the callee is a shared method, then its static cctor
9560                          * might not get called after the call was patched.
9561                          */
9562                         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)) {
9563                                 emit_class_init (cfg, cmethod->klass);
9564                                 CHECK_TYPELOAD (cmethod->klass);
9565                         }
9566
9567                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9568
9569                         if (cfg->gshared) {
9570                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9571
9572                                 context_used = mini_method_check_context_used (cfg, cmethod);
9573
9574                                 if (context_used && mono_class_is_interface (cmethod->klass)) {
9575                                         /* Generic method interface
9576                                            calls are resolved via a
9577                                            helper function and don't
9578                                            need an imt. */
9579                                         if (!cmethod_context || !cmethod_context->method_inst)
9580                                                 pass_imt_from_rgctx = TRUE;
9581                                 }
9582
9583                                 /*
9584                                  * If a shared method calls another
9585                                  * shared method then the caller must
9586                                  * have a generic sharing context
9587                                  * because the magic trampoline
9588                                  * requires it.  FIXME: We shouldn't
9589                                  * have to force the vtable/mrgctx
9590                                  * variable here.  Instead there
9591                                  * should be a flag in the cfg to
9592                                  * request a generic sharing context.
9593                                  */
9594                                 if (context_used &&
9595                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9596                                         mono_get_vtable_var (cfg);
9597                         }
9598
9599                         if (pass_vtable) {
9600                                 if (context_used) {
9601                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9602                                 } else {
9603                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9604
9605                                         CHECK_TYPELOAD (cmethod->klass);
9606                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9607                                 }
9608                         }
9609
9610                         if (pass_mrgctx) {
9611                                 g_assert (!vtable_arg);
9612
9613                                 if (!cfg->compile_aot) {
9614                                         /* 
9615                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9616                                          * for type load errors before.
9617                                          */
9618                                         mono_class_setup_vtable (cmethod->klass);
9619                                         CHECK_TYPELOAD (cmethod->klass);
9620                                 }
9621
9622                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9623
9624                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9625                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9626                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9627                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9628                                         if (virtual_)
9629                                                 check_this = TRUE;
9630                                         virtual_ = 0;
9631                                 }
9632                         }
9633
9634                         if (pass_imt_from_rgctx) {
9635                                 g_assert (!pass_vtable);
9636
9637                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9638                                         cmethod, MONO_RGCTX_INFO_METHOD);
9639                         }
9640
9641                         if (check_this)
9642                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9643
9644                         /* Calling virtual generic methods */
9645                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9646                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9647                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9648                             fsig->generic_param_count && 
9649                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9650                                 !cfg->llvm_only) {
9651                                 MonoInst *this_temp, *this_arg_temp, *store;
9652                                 MonoInst *iargs [4];
9653
9654                                 g_assert (fsig->is_inflated);
9655
9656                                 /* Prevent inlining of methods that contain indirect calls */
9657                                 INLINE_FAILURE ("virtual generic call");
9658
9659                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9660                                         GSHAREDVT_FAILURE (*ip);
9661
9662                                 if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9663                                         g_assert (!imt_arg);
9664                                         if (!context_used)
9665                                                 g_assert (cmethod->is_inflated);
9666                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9667                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9668                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9669                                 } else {
9670                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9671                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9672                                         MONO_ADD_INS (cfg->cbb, store);
9673
9674                                         /* FIXME: This should be a managed pointer */
9675                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9676
9677                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9678                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9679                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9680                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9681                                         addr = mono_emit_jit_icall (cfg,
9682                                                                                                 mono_helper_compile_generic_method, iargs);
9683
9684                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9685
9686                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9687                                 }
9688
9689                                 goto call_end;
9690                         }
9691
9692                         /*
9693                          * Implement a workaround for the inherent races involved in locking:
9694                          * Monitor.Enter ()
9695                          * try {
9696                          * } finally {
9697                          *    Monitor.Exit ()
9698                          * }
9699                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9700                          * try block, the Exit () won't be executed, see:
9701                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9702                          * To work around this, we extend such try blocks to include the last x bytes
9703                          * of the Monitor.Enter () call.
9704                          */
9705                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9706                                 MonoBasicBlock *tbb;
9707
9708                                 GET_BBLOCK (cfg, tbb, ip + 5);
9709                                 /* 
9710                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9711                                  * from Monitor.Enter like ArgumentNullException.
9712                                  */
9713                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9714                                         /* Mark this bblock as needing to be extended */
9715                                         tbb->extend_try_block = TRUE;
9716                                 }
9717                         }
9718
9719                         /* Conversion to a JIT intrinsic */
9720                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9721                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9722                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9723                                         emit_widen = FALSE;
9724                                 }
9725                                 goto call_end;
9726                         }
9727                         CHECK_CFG_ERROR;
9728                         
9729                         /* Inlining */
9730                         if ((cfg->opt & MONO_OPT_INLINE) &&
9731                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9732                             mono_method_check_inlining (cfg, cmethod)) {
9733                                 int costs;
9734                                 gboolean always = FALSE;
9735
9736                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9737                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9738                                         /* Prevent inlining of methods that call wrappers */
9739                                         INLINE_FAILURE ("wrapper call");
9740                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9741                                         always = TRUE;
9742                                 }
9743
9744                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9745                                 if (costs) {
9746                                         cfg->real_offset += 5;
9747
9748                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9749                                                 /* *sp is already set by inline_method */
9750                                                 sp++;
9751                                                 push_res = FALSE;
9752                                         }
9753
9754                                         inline_costs += costs;
9755
9756                                         goto call_end;
9757                                 }
9758                         }
9759
9760                         /* Tail recursion elimination */
9761                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9762                                 gboolean has_vtargs = FALSE;
9763                                 int i;
9764
9765                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9766                                 INLINE_FAILURE ("tail call");
9767
9768                                 /* keep it simple */
9769                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9770                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9771                                                 has_vtargs = TRUE;
9772                                 }
9773
9774                                 if (!has_vtargs) {
9775                                         if (need_seq_point) {
9776                                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9777                                                 need_seq_point = FALSE;
9778                                         }
9779                                         for (i = 0; i < n; ++i)
9780                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9781                                         MONO_INST_NEW (cfg, ins, OP_BR);
9782                                         MONO_ADD_INS (cfg->cbb, ins);
9783                                         tblock = start_bblock->out_bb [0];
9784                                         link_bblock (cfg, cfg->cbb, tblock);
9785                                         ins->inst_target_bb = tblock;
9786                                         start_new_bblock = 1;
9787
9788                                         /* skip the CEE_RET, too */
9789                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9790                                                 skip_ret = TRUE;
9791                                         push_res = FALSE;
9792                                         goto call_end;
9793                                 }
9794                         }
9795
9796                         inline_costs += 10 * num_calls++;
9797
9798                         /*
9799                          * Synchronized wrappers.
9800                          * Its hard to determine where to replace a method with its synchronized
9801                          * wrapper without causing an infinite recursion. The current solution is
9802                          * to add the synchronized wrapper in the trampolines, and to
9803                          * change the called method to a dummy wrapper, and resolve that wrapper
9804                          * to the real method in mono_jit_compile_method ().
9805                          */
9806                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9807                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9808                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9809                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9810                         }
9811
9812                         /*
9813                          * Making generic calls out of gsharedvt methods.
9814                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9815                          * patching gshared method addresses into a gsharedvt method.
9816                          */
9817                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) &&
9818                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9819                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9820                                 MonoRgctxInfoType info_type;
9821
9822                                 if (virtual_) {
9823                                         //if (mono_class_is_interface (cmethod->klass))
9824                                                 //GSHAREDVT_FAILURE (*ip);
9825                                         // disable for possible remoting calls
9826                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9827                                                 GSHAREDVT_FAILURE (*ip);
9828                                         if (fsig->generic_param_count) {
9829                                                 /* virtual generic call */
9830                                                 g_assert (!imt_arg);
9831                                                 /* Same as the virtual generic case above */
9832                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9833                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9834                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9835                                                 vtable_arg = NULL;
9836                                         } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) {
9837                                                 /* This can happen when we call a fully instantiated iface method */
9838                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9839                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9840                                                 vtable_arg = NULL;
9841                                         }
9842                                 }
9843
9844                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9845                                         keep_this_alive = sp [0];
9846
9847                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9848                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9849                                 else
9850                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9851                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9852
9853                                 if (cfg->llvm_only) {
9854                                         // FIXME: Avoid initializing vtable_arg
9855                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9856                                 } else {
9857                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9858                                 }
9859                                 goto call_end;
9860                         }
9861
9862                         /* Generic sharing */
9863
9864                         /*
9865                          * Use this if the callee is gsharedvt sharable too, since
9866                          * at runtime we might find an instantiation so the call cannot
9867                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9868                          */
9869                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9870                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9871                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9872                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9873                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9874                                 INLINE_FAILURE ("gshared");
9875
9876                                 g_assert (cfg->gshared && cmethod);
9877                                 g_assert (!addr);
9878
9879                                 /*
9880                                  * We are compiling a call to a
9881                                  * generic method from shared code,
9882                                  * which means that we have to look up
9883                                  * the method in the rgctx and do an
9884                                  * indirect call.
9885                                  */
9886                                 if (fsig->hasthis)
9887                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9888
9889                                 if (cfg->llvm_only) {
9890                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9891                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9892                                         else
9893                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9894                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9895                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9896                                 } else {
9897                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9898                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9899                                 }
9900                                 goto call_end;
9901                         }
9902
9903                         /* Direct calls to icalls */
9904                         if (direct_icall) {
9905                                 MonoMethod *wrapper;
9906                                 int costs;
9907
9908                                 /* Inline the wrapper */
9909                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9910
9911                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9912                                 g_assert (costs > 0);
9913                                 cfg->real_offset += 5;
9914
9915                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9916                                         /* *sp is already set by inline_method */
9917                                         sp++;
9918                                         push_res = FALSE;
9919                                 }
9920
9921                                 inline_costs += costs;
9922
9923                                 goto call_end;
9924                         }
9925                                         
9926                         /* Array methods */
9927                         if (array_rank) {
9928                                 MonoInst *addr;
9929
9930                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9931                                         MonoInst *val = sp [fsig->param_count];
9932
9933                                         if (val->type == STACK_OBJ) {
9934                                                 MonoInst *iargs [2];
9935
9936                                                 iargs [0] = sp [0];
9937                                                 iargs [1] = val;
9938                                                 
9939                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9940                                         }
9941                                         
9942                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9943                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9944                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
9945                                                 emit_write_barrier (cfg, addr, val);
9946                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9947                                                 GSHAREDVT_FAILURE (*ip);
9948                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9949                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9950
9951                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9952                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9953                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9954                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9955                                         CHECK_TYPELOAD (cmethod->klass);
9956                                         
9957                                         readonly = FALSE;
9958                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9959                                         ins = addr;
9960                                 } else {
9961                                         g_assert_not_reached ();
9962                                 }
9963
9964                                 emit_widen = FALSE;
9965                                 goto call_end;
9966                         }
9967
9968                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9969                         if (ins)
9970                                 goto call_end;
9971
9972                         /* Tail prefix / tail call optimization */
9973
9974                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9975                         /* FIXME: runtime generic context pointer for jumps? */
9976                         /* FIXME: handle this for generic sharing eventually */
9977                         if ((ins_flag & MONO_INST_TAILCALL) &&
9978                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9979                                 supported_tail_call = TRUE;
9980
9981                         if (supported_tail_call) {
9982                                 MonoCallInst *call;
9983
9984                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9985                                 INLINE_FAILURE ("tail call");
9986
9987                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9988
9989                                 if (cfg->backend->have_op_tail_call) {
9990                                         /* Handle tail calls similarly to normal calls */
9991                                         tail_call = TRUE;
9992                                 } else {
9993                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9994
9995                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9996                                         call->tail_call = TRUE;
9997                                         call->method = cmethod;
9998                                         call->signature = mono_method_signature (cmethod);
9999
10000                                         /*
10001                                          * We implement tail calls by storing the actual arguments into the 
10002                                          * argument variables, then emitting a CEE_JMP.
10003                                          */
10004                                         for (i = 0; i < n; ++i) {
10005                                                 /* Prevent argument from being register allocated */
10006                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
10007                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
10008                                         }
10009                                         ins = (MonoInst*)call;
10010                                         ins->inst_p0 = cmethod;
10011                                         ins->inst_p1 = arg_array [0];
10012                                         MONO_ADD_INS (cfg->cbb, ins);
10013                                         link_bblock (cfg, cfg->cbb, end_bblock);
10014                                         start_new_bblock = 1;
10015
10016                                         // FIXME: Eliminate unreachable epilogs
10017
10018                                         /*
10019                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
10020                                          * only reachable from this call.
10021                                          */
10022                                         GET_BBLOCK (cfg, tblock, ip + 5);
10023                                         if (tblock == cfg->cbb || tblock->in_count == 0)
10024                                                 skip_ret = TRUE;
10025                                         push_res = FALSE;
10026
10027                                         goto call_end;
10028                                 }
10029                         }
10030
10031                         /*
10032                          * Virtual calls in llvm-only mode.
10033                          */
10034                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
10035                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
10036                                 goto call_end;
10037                         }
10038
10039                         /* Common call */
10040                         if (!(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
10041                                 INLINE_FAILURE ("call");
10042                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
10043                                                                                           imt_arg, vtable_arg);
10044
10045                         if (tail_call && !cfg->llvm_only) {
10046                                 link_bblock (cfg, cfg->cbb, end_bblock);
10047                                 start_new_bblock = 1;
10048
10049                                 // FIXME: Eliminate unreachable epilogs
10050
10051                                 /*
10052                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
10053                                  * only reachable from this call.
10054                                  */
10055                                 GET_BBLOCK (cfg, tblock, ip + 5);
10056                                 if (tblock == cfg->cbb || tblock->in_count == 0)
10057                                         skip_ret = TRUE;
10058                                 push_res = FALSE;
10059                         }
10060
10061                         call_end:
10062
10063                         /* End of call, INS should contain the result of the call, if any */
10064
10065                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
10066                                 g_assert (ins);
10067                                 if (emit_widen)
10068                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
10069                                 else
10070                                         *sp++ = ins;
10071                         }
10072
10073                         if (keep_this_alive) {
10074                                 MonoInst *dummy_use;
10075
10076                                 /* See mono_emit_method_call_full () */
10077                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10078                         }
10079
10080                         if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
10081                                 /*
10082                                  * Clang can convert these calls to tail calls which screw up the stack
10083                                  * walk. This happens even when the -fno-optimize-sibling-calls
10084                                  * option is passed to clang.
10085                                  * Work around this by emitting a dummy call.
10086                                  */
10087                                 mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
10088                         }
10089
10090                         CHECK_CFG_EXCEPTION;
10091
10092                         ip += 5;
10093                         if (skip_ret) {
10094                                 g_assert (*ip == CEE_RET);
10095                                 ip += 1;
10096                         }
10097                         ins_flag = 0;
10098                         constrained_class = NULL;
10099                         if (need_seq_point)
10100                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10101                         break;
10102                 }
10103                 case CEE_RET:
10104                         if (cfg->method != method) {
10105                                 /* return from inlined method */
10106                                 /* 
10107                                  * If in_count == 0, that means the ret is unreachable due to
10108                                  * being preceeded by a throw. In that case, inline_method () will
10109                                  * handle setting the return value 
10110                                  * (test case: test_0_inline_throw ()).
10111                                  */
10112                                 if (return_var && cfg->cbb->in_count) {
10113                                         MonoType *ret_type = mono_method_signature (method)->ret;
10114
10115                                         MonoInst *store;
10116                                         CHECK_STACK (1);
10117                                         --sp;
10118
10119                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10120                                                 UNVERIFIED;
10121
10122                                         //g_assert (returnvar != -1);
10123                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10124                                         cfg->ret_var_set = TRUE;
10125                                 } 
10126                         } else {
10127                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10128
10129                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10130                                         emit_pop_lmf (cfg);
10131
10132                                 if (cfg->ret) {
10133                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10134
10135                                         if (seq_points && !sym_seq_points) {
10136                                                 /* 
10137                                                  * Place a seq point here too even through the IL stack is not
10138                                                  * empty, so a step over on
10139                                                  * call <FOO>
10140                                                  * ret
10141                                                  * will work correctly.
10142                                                  */
10143                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10144                                                 MONO_ADD_INS (cfg->cbb, ins);
10145                                         }
10146
10147                                         g_assert (!return_var);
10148                                         CHECK_STACK (1);
10149                                         --sp;
10150
10151                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10152                                                 UNVERIFIED;
10153
10154                                         emit_setret (cfg, *sp);
10155                                 }
10156                         }
10157                         if (sp != stack_start)
10158                                 UNVERIFIED;
10159                         MONO_INST_NEW (cfg, ins, OP_BR);
10160                         ip++;
10161                         ins->inst_target_bb = end_bblock;
10162                         MONO_ADD_INS (cfg->cbb, ins);
10163                         link_bblock (cfg, cfg->cbb, end_bblock);
10164                         start_new_bblock = 1;
10165                         break;
10166                 case CEE_BR_S:
10167                         CHECK_OPSIZE (2);
10168                         MONO_INST_NEW (cfg, ins, OP_BR);
10169                         ip++;
10170                         target = ip + 1 + (signed char)(*ip);
10171                         ++ip;
10172                         GET_BBLOCK (cfg, tblock, target);
10173                         link_bblock (cfg, cfg->cbb, tblock);
10174                         ins->inst_target_bb = tblock;
10175                         if (sp != stack_start) {
10176                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10177                                 sp = stack_start;
10178                                 CHECK_UNVERIFIABLE (cfg);
10179                         }
10180                         MONO_ADD_INS (cfg->cbb, ins);
10181                         start_new_bblock = 1;
10182                         inline_costs += BRANCH_COST;
10183                         break;
10184                 case CEE_BEQ_S:
10185                 case CEE_BGE_S:
10186                 case CEE_BGT_S:
10187                 case CEE_BLE_S:
10188                 case CEE_BLT_S:
10189                 case CEE_BNE_UN_S:
10190                 case CEE_BGE_UN_S:
10191                 case CEE_BGT_UN_S:
10192                 case CEE_BLE_UN_S:
10193                 case CEE_BLT_UN_S:
10194                         CHECK_OPSIZE (2);
10195                         CHECK_STACK (2);
10196                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10197                         ip++;
10198                         target = ip + 1 + *(signed char*)ip;
10199                         ip++;
10200
10201                         ADD_BINCOND (NULL);
10202
10203                         sp = stack_start;
10204                         inline_costs += BRANCH_COST;
10205                         break;
10206                 case CEE_BR:
10207                         CHECK_OPSIZE (5);
10208                         MONO_INST_NEW (cfg, ins, OP_BR);
10209                         ip++;
10210
10211                         target = ip + 4 + (gint32)read32(ip);
10212                         ip += 4;
10213                         GET_BBLOCK (cfg, tblock, target);
10214                         link_bblock (cfg, cfg->cbb, tblock);
10215                         ins->inst_target_bb = tblock;
10216                         if (sp != stack_start) {
10217                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10218                                 sp = stack_start;
10219                                 CHECK_UNVERIFIABLE (cfg);
10220                         }
10221
10222                         MONO_ADD_INS (cfg->cbb, ins);
10223
10224                         start_new_bblock = 1;
10225                         inline_costs += BRANCH_COST;
10226                         break;
10227                 case CEE_BRFALSE_S:
10228                 case CEE_BRTRUE_S:
10229                 case CEE_BRFALSE:
10230                 case CEE_BRTRUE: {
10231                         MonoInst *cmp;
10232                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10233                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10234                         guint32 opsize = is_short ? 1 : 4;
10235
10236                         CHECK_OPSIZE (opsize);
10237                         CHECK_STACK (1);
10238                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10239                                 UNVERIFIED;
10240                         ip ++;
10241                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10242                         ip += opsize;
10243
10244                         sp--;
10245
10246                         GET_BBLOCK (cfg, tblock, target);
10247                         link_bblock (cfg, cfg->cbb, tblock);
10248                         GET_BBLOCK (cfg, tblock, ip);
10249                         link_bblock (cfg, cfg->cbb, tblock);
10250
10251                         if (sp != stack_start) {
10252                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10253                                 CHECK_UNVERIFIABLE (cfg);
10254                         }
10255
10256                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10257                         cmp->sreg1 = sp [0]->dreg;
10258                         type_from_op (cfg, cmp, sp [0], NULL);
10259                         CHECK_TYPE (cmp);
10260
10261 #if SIZEOF_REGISTER == 4
10262                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10263                                 /* Convert it to OP_LCOMPARE */
10264                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10265                                 ins->type = STACK_I8;
10266                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10267                                 ins->inst_l = 0;
10268                                 MONO_ADD_INS (cfg->cbb, ins);
10269                                 cmp->opcode = OP_LCOMPARE;
10270                                 cmp->sreg2 = ins->dreg;
10271                         }
10272 #endif
10273                         MONO_ADD_INS (cfg->cbb, cmp);
10274
10275                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10276                         type_from_op (cfg, ins, sp [0], NULL);
10277                         MONO_ADD_INS (cfg->cbb, ins);
10278                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10279                         GET_BBLOCK (cfg, tblock, target);
10280                         ins->inst_true_bb = tblock;
10281                         GET_BBLOCK (cfg, tblock, ip);
10282                         ins->inst_false_bb = tblock;
10283                         start_new_bblock = 2;
10284
10285                         sp = stack_start;
10286                         inline_costs += BRANCH_COST;
10287                         break;
10288                 }
10289                 case CEE_BEQ:
10290                 case CEE_BGE:
10291                 case CEE_BGT:
10292                 case CEE_BLE:
10293                 case CEE_BLT:
10294                 case CEE_BNE_UN:
10295                 case CEE_BGE_UN:
10296                 case CEE_BGT_UN:
10297                 case CEE_BLE_UN:
10298                 case CEE_BLT_UN:
10299                         CHECK_OPSIZE (5);
10300                         CHECK_STACK (2);
10301                         MONO_INST_NEW (cfg, ins, *ip);
10302                         ip++;
10303                         target = ip + 4 + (gint32)read32(ip);
10304                         ip += 4;
10305
10306                         ADD_BINCOND (NULL);
10307
10308                         sp = stack_start;
10309                         inline_costs += BRANCH_COST;
10310                         break;
10311                 case CEE_SWITCH: {
10312                         MonoInst *src1;
10313                         MonoBasicBlock **targets;
10314                         MonoBasicBlock *default_bblock;
10315                         MonoJumpInfoBBTable *table;
10316                         int offset_reg = alloc_preg (cfg);
10317                         int target_reg = alloc_preg (cfg);
10318                         int table_reg = alloc_preg (cfg);
10319                         int sum_reg = alloc_preg (cfg);
10320                         gboolean use_op_switch;
10321
10322                         CHECK_OPSIZE (5);
10323                         CHECK_STACK (1);
10324                         n = read32 (ip + 1);
10325                         --sp;
10326                         src1 = sp [0];
10327                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10328                                 UNVERIFIED;
10329
10330                         ip += 5;
10331                         CHECK_OPSIZE (n * sizeof (guint32));
10332                         target = ip + n * sizeof (guint32);
10333
10334                         GET_BBLOCK (cfg, default_bblock, target);
10335                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10336
10337                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10338                         for (i = 0; i < n; ++i) {
10339                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10340                                 targets [i] = tblock;
10341                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10342                                 ip += 4;
10343                         }
10344
10345                         if (sp != stack_start) {
10346                                 /* 
10347                                  * Link the current bb with the targets as well, so handle_stack_args
10348                                  * will set their in_stack correctly.
10349                                  */
10350                                 link_bblock (cfg, cfg->cbb, default_bblock);
10351                                 for (i = 0; i < n; ++i)
10352                                         link_bblock (cfg, cfg->cbb, targets [i]);
10353
10354                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10355                                 sp = stack_start;
10356                                 CHECK_UNVERIFIABLE (cfg);
10357
10358                                 /* Undo the links */
10359                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10360                                 for (i = 0; i < n; ++i)
10361                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10362                         }
10363
10364                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10365                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10366
10367                         for (i = 0; i < n; ++i)
10368                                 link_bblock (cfg, cfg->cbb, targets [i]);
10369
10370                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10371                         table->table = targets;
10372                         table->table_size = n;
10373
10374                         use_op_switch = FALSE;
10375 #ifdef TARGET_ARM
10376                         /* ARM implements SWITCH statements differently */
10377                         /* FIXME: Make it use the generic implementation */
10378                         if (!cfg->compile_aot)
10379                                 use_op_switch = TRUE;
10380 #endif
10381
10382                         if (COMPILE_LLVM (cfg))
10383                                 use_op_switch = TRUE;
10384
10385                         cfg->cbb->has_jump_table = 1;
10386
10387                         if (use_op_switch) {
10388                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10389                                 ins->sreg1 = src1->dreg;
10390                                 ins->inst_p0 = table;
10391                                 ins->inst_many_bb = targets;
10392                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10393                                 MONO_ADD_INS (cfg->cbb, ins);
10394                         } else {
10395                                 if (sizeof (gpointer) == 8)
10396                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10397                                 else
10398                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10399
10400 #if SIZEOF_REGISTER == 8
10401                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10402                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10403 #endif
10404
10405                                 if (cfg->compile_aot) {
10406                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10407                                 } else {
10408                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10409                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10410                                         ins->inst_p0 = table;
10411                                         ins->dreg = table_reg;
10412                                         MONO_ADD_INS (cfg->cbb, ins);
10413                                 }
10414
10415                                 /* FIXME: Use load_memindex */
10416                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10417                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10418                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10419                         }
10420                         start_new_bblock = 1;
10421                         inline_costs += (BRANCH_COST * 2);
10422                         break;
10423                 }
10424                 case CEE_LDIND_I1:
10425                 case CEE_LDIND_U1:
10426                 case CEE_LDIND_I2:
10427                 case CEE_LDIND_U2:
10428                 case CEE_LDIND_I4:
10429                 case CEE_LDIND_U4:
10430                 case CEE_LDIND_I8:
10431                 case CEE_LDIND_I:
10432                 case CEE_LDIND_R4:
10433                 case CEE_LDIND_R8:
10434                 case CEE_LDIND_REF:
10435                         CHECK_STACK (1);
10436                         --sp;
10437
10438                         switch (*ip) {
10439                         case CEE_LDIND_R4:
10440                         case CEE_LDIND_R8:
10441                                 dreg = alloc_freg (cfg);
10442                                 break;
10443                         case CEE_LDIND_I8:
10444                                 dreg = alloc_lreg (cfg);
10445                                 break;
10446                         case CEE_LDIND_REF:
10447                                 dreg = alloc_ireg_ref (cfg);
10448                                 break;
10449                         default:
10450                                 dreg = alloc_preg (cfg);
10451                         }
10452
10453                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10454                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10455                         if (*ip == CEE_LDIND_R4)
10456                                 ins->type = cfg->r4_stack_type;
10457                         ins->flags |= ins_flag;
10458                         MONO_ADD_INS (cfg->cbb, ins);
10459                         *sp++ = ins;
10460                         if (ins_flag & MONO_INST_VOLATILE) {
10461                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10462                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10463                         }
10464                         ins_flag = 0;
10465                         ++ip;
10466                         break;
10467                 case CEE_STIND_REF:
10468                 case CEE_STIND_I1:
10469                 case CEE_STIND_I2:
10470                 case CEE_STIND_I4:
10471                 case CEE_STIND_I8:
10472                 case CEE_STIND_R4:
10473                 case CEE_STIND_R8:
10474                 case CEE_STIND_I:
10475                         CHECK_STACK (2);
10476                         sp -= 2;
10477
10478                         if (ins_flag & MONO_INST_VOLATILE) {
10479                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10480                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10481                         }
10482
10483                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10484                         ins->flags |= ins_flag;
10485                         ins_flag = 0;
10486
10487                         MONO_ADD_INS (cfg->cbb, ins);
10488
10489                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
10490                                 emit_write_barrier (cfg, sp [0], sp [1]);
10491
10492                         inline_costs += 1;
10493                         ++ip;
10494                         break;
10495
10496                 case CEE_MUL:
10497                         CHECK_STACK (2);
10498
10499                         MONO_INST_NEW (cfg, ins, (*ip));
10500                         sp -= 2;
10501                         ins->sreg1 = sp [0]->dreg;
10502                         ins->sreg2 = sp [1]->dreg;
10503                         type_from_op (cfg, ins, sp [0], sp [1]);
10504                         CHECK_TYPE (ins);
10505                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10506
10507                         /* Use the immediate opcodes if possible */
10508                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10509                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10510                                 if (imm_opcode != -1) {
10511                                         ins->opcode = imm_opcode;
10512                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10513                                         ins->sreg2 = -1;
10514
10515                                         NULLIFY_INS (sp [1]);
10516                                 }
10517                         }
10518
10519                         MONO_ADD_INS ((cfg)->cbb, (ins));
10520
10521                         *sp++ = mono_decompose_opcode (cfg, ins);
10522                         ip++;
10523                         break;
10524                 case CEE_ADD:
10525                 case CEE_SUB:
10526                 case CEE_DIV:
10527                 case CEE_DIV_UN:
10528                 case CEE_REM:
10529                 case CEE_REM_UN:
10530                 case CEE_AND:
10531                 case CEE_OR:
10532                 case CEE_XOR:
10533                 case CEE_SHL:
10534                 case CEE_SHR:
10535                 case CEE_SHR_UN:
10536                         CHECK_STACK (2);
10537
10538                         MONO_INST_NEW (cfg, ins, (*ip));
10539                         sp -= 2;
10540                         ins->sreg1 = sp [0]->dreg;
10541                         ins->sreg2 = sp [1]->dreg;
10542                         type_from_op (cfg, ins, sp [0], sp [1]);
10543                         CHECK_TYPE (ins);
10544                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10545                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10546
10547                         /* FIXME: Pass opcode to is_inst_imm */
10548
10549                         /* Use the immediate opcodes if possible */
10550                         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)) {
10551                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10552                                 if (imm_opcode != -1) {
10553                                         ins->opcode = imm_opcode;
10554                                         if (sp [1]->opcode == OP_I8CONST) {
10555 #if SIZEOF_REGISTER == 8
10556                                                 ins->inst_imm = sp [1]->inst_l;
10557 #else
10558                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10559                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10560 #endif
10561                                         }
10562                                         else
10563                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10564                                         ins->sreg2 = -1;
10565
10566                                         /* Might be followed by an instruction added by add_widen_op */
10567                                         if (sp [1]->next == NULL)
10568                                                 NULLIFY_INS (sp [1]);
10569                                 }
10570                         }
10571                         MONO_ADD_INS ((cfg)->cbb, (ins));
10572
10573                         *sp++ = mono_decompose_opcode (cfg, ins);
10574                         ip++;
10575                         break;
10576                 case CEE_NEG:
10577                 case CEE_NOT:
10578                 case CEE_CONV_I1:
10579                 case CEE_CONV_I2:
10580                 case CEE_CONV_I4:
10581                 case CEE_CONV_R4:
10582                 case CEE_CONV_R8:
10583                 case CEE_CONV_U4:
10584                 case CEE_CONV_I8:
10585                 case CEE_CONV_U8:
10586                 case CEE_CONV_OVF_I8:
10587                 case CEE_CONV_OVF_U8:
10588                 case CEE_CONV_R_UN:
10589                         CHECK_STACK (1);
10590
10591                         /* Special case this earlier so we have long constants in the IR */
10592                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10593                                 int data = sp [-1]->inst_c0;
10594                                 sp [-1]->opcode = OP_I8CONST;
10595                                 sp [-1]->type = STACK_I8;
10596 #if SIZEOF_REGISTER == 8
10597                                 if ((*ip) == CEE_CONV_U8)
10598                                         sp [-1]->inst_c0 = (guint32)data;
10599                                 else
10600                                         sp [-1]->inst_c0 = data;
10601 #else
10602                                 sp [-1]->inst_ls_word = data;
10603                                 if ((*ip) == CEE_CONV_U8)
10604                                         sp [-1]->inst_ms_word = 0;
10605                                 else
10606                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10607 #endif
10608                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10609                         }
10610                         else {
10611                                 ADD_UNOP (*ip);
10612                         }
10613                         ip++;
10614                         break;
10615                 case CEE_CONV_OVF_I4:
10616                 case CEE_CONV_OVF_I1:
10617                 case CEE_CONV_OVF_I2:
10618                 case CEE_CONV_OVF_I:
10619                 case CEE_CONV_OVF_U:
10620                         CHECK_STACK (1);
10621
10622                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10623                                 ADD_UNOP (CEE_CONV_OVF_I8);
10624                                 ADD_UNOP (*ip);
10625                         } else {
10626                                 ADD_UNOP (*ip);
10627                         }
10628                         ip++;
10629                         break;
10630                 case CEE_CONV_OVF_U1:
10631                 case CEE_CONV_OVF_U2:
10632                 case CEE_CONV_OVF_U4:
10633                         CHECK_STACK (1);
10634
10635                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10636                                 ADD_UNOP (CEE_CONV_OVF_U8);
10637                                 ADD_UNOP (*ip);
10638                         } else {
10639                                 ADD_UNOP (*ip);
10640                         }
10641                         ip++;
10642                         break;
10643                 case CEE_CONV_OVF_I1_UN:
10644                 case CEE_CONV_OVF_I2_UN:
10645                 case CEE_CONV_OVF_I4_UN:
10646                 case CEE_CONV_OVF_I8_UN:
10647                 case CEE_CONV_OVF_U1_UN:
10648                 case CEE_CONV_OVF_U2_UN:
10649                 case CEE_CONV_OVF_U4_UN:
10650                 case CEE_CONV_OVF_U8_UN:
10651                 case CEE_CONV_OVF_I_UN:
10652                 case CEE_CONV_OVF_U_UN:
10653                 case CEE_CONV_U2:
10654                 case CEE_CONV_U1:
10655                 case CEE_CONV_I:
10656                 case CEE_CONV_U:
10657                         CHECK_STACK (1);
10658                         ADD_UNOP (*ip);
10659                         CHECK_CFG_EXCEPTION;
10660                         ip++;
10661                         break;
10662                 case CEE_ADD_OVF:
10663                 case CEE_ADD_OVF_UN:
10664                 case CEE_MUL_OVF:
10665                 case CEE_MUL_OVF_UN:
10666                 case CEE_SUB_OVF:
10667                 case CEE_SUB_OVF_UN:
10668                         CHECK_STACK (2);
10669                         ADD_BINOP (*ip);
10670                         ip++;
10671                         break;
10672                 case CEE_CPOBJ:
10673                         GSHAREDVT_FAILURE (*ip);
10674                         CHECK_OPSIZE (5);
10675                         CHECK_STACK (2);
10676                         token = read32 (ip + 1);
10677                         klass = mini_get_class (method, token, generic_context);
10678                         CHECK_TYPELOAD (klass);
10679                         sp -= 2;
10680                         if (generic_class_is_reference_type (cfg, klass)) {
10681                                 MonoInst *store, *load;
10682                                 int dreg = alloc_ireg_ref (cfg);
10683
10684                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10685                                 load->flags |= ins_flag;
10686                                 MONO_ADD_INS (cfg->cbb, load);
10687
10688                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10689                                 store->flags |= ins_flag;
10690                                 MONO_ADD_INS (cfg->cbb, store);
10691
10692                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10693                                         emit_write_barrier (cfg, sp [0], sp [1]);
10694                         } else {
10695                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10696                         }
10697                         ins_flag = 0;
10698                         ip += 5;
10699                         break;
10700                 case CEE_LDOBJ: {
10701                         int loc_index = -1;
10702                         int stloc_len = 0;
10703
10704                         CHECK_OPSIZE (5);
10705                         CHECK_STACK (1);
10706                         --sp;
10707                         token = read32 (ip + 1);
10708                         klass = mini_get_class (method, token, generic_context);
10709                         CHECK_TYPELOAD (klass);
10710
10711                         /* Optimize the common ldobj+stloc combination */
10712                         switch (ip [5]) {
10713                         case CEE_STLOC_S:
10714                                 loc_index = ip [6];
10715                                 stloc_len = 2;
10716                                 break;
10717                         case CEE_STLOC_0:
10718                         case CEE_STLOC_1:
10719                         case CEE_STLOC_2:
10720                         case CEE_STLOC_3:
10721                                 loc_index = ip [5] - CEE_STLOC_0;
10722                                 stloc_len = 1;
10723                                 break;
10724                         default:
10725                                 break;
10726                         }
10727
10728                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10729                                 CHECK_LOCAL (loc_index);
10730
10731                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10732                                 ins->dreg = cfg->locals [loc_index]->dreg;
10733                                 ins->flags |= ins_flag;
10734                                 ip += 5;
10735                                 ip += stloc_len;
10736                                 if (ins_flag & MONO_INST_VOLATILE) {
10737                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10738                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10739                                 }
10740                                 ins_flag = 0;
10741                                 break;
10742                         }
10743
10744                         /* Optimize the ldobj+stobj combination */
10745                         /* The reference case ends up being a load+store anyway */
10746                         /* Skip this if the operation is volatile. */
10747                         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)) {
10748                                 CHECK_STACK (1);
10749
10750                                 sp --;
10751
10752                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10753
10754                                 ip += 5 + 5;
10755                                 ins_flag = 0;
10756                                 break;
10757                         }
10758
10759                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10760                         ins->flags |= ins_flag;
10761                         *sp++ = ins;
10762
10763                         if (ins_flag & MONO_INST_VOLATILE) {
10764                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10765                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10766                         }
10767
10768                         ip += 5;
10769                         ins_flag = 0;
10770                         inline_costs += 1;
10771                         break;
10772                 }
10773                 case CEE_LDSTR:
10774                         CHECK_STACK_OVF (1);
10775                         CHECK_OPSIZE (5);
10776                         n = read32 (ip + 1);
10777
10778                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10779                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10780                                 ins->type = STACK_OBJ;
10781                                 *sp = ins;
10782                         }
10783                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10784                                 MonoInst *iargs [1];
10785                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10786
10787                                 if (cfg->compile_aot)
10788                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10789                                 else
10790                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10791                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10792                         } else {
10793                                 if (cfg->opt & MONO_OPT_SHARED) {
10794                                         MonoInst *iargs [3];
10795
10796                                         if (cfg->compile_aot) {
10797                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10798                                         }
10799                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10800                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10801                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10802                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10803                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10804                                         CHECK_CFG_ERROR;
10805                                 } else {
10806                                         if (cfg->cbb->out_of_line) {
10807                                                 MonoInst *iargs [2];
10808
10809                                                 if (image == mono_defaults.corlib) {
10810                                                         /* 
10811                                                          * Avoid relocations in AOT and save some space by using a 
10812                                                          * version of helper_ldstr specialized to mscorlib.
10813                                                          */
10814                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10815                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10816                                                 } else {
10817                                                         /* Avoid creating the string object */
10818                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10819                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10820                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10821                                                 }
10822                                         } 
10823                                         else
10824                                         if (cfg->compile_aot) {
10825                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10826                                                 *sp = ins;
10827                                                 MONO_ADD_INS (cfg->cbb, ins);
10828                                         } 
10829                                         else {
10830                                                 NEW_PCONST (cfg, ins, NULL);
10831                                                 ins->type = STACK_OBJ;
10832                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10833                                                 CHECK_CFG_ERROR;
10834                                                 
10835                                                 if (!ins->inst_p0)
10836                                                         OUT_OF_MEMORY_FAILURE;
10837
10838                                                 *sp = ins;
10839                                                 MONO_ADD_INS (cfg->cbb, ins);
10840                                         }
10841                                 }
10842                         }
10843
10844                         sp++;
10845                         ip += 5;
10846                         break;
10847                 case CEE_NEWOBJ: {
10848                         MonoInst *iargs [2];
10849                         MonoMethodSignature *fsig;
10850                         MonoInst this_ins;
10851                         MonoInst *alloc;
10852                         MonoInst *vtable_arg = NULL;
10853
10854                         CHECK_OPSIZE (5);
10855                         token = read32 (ip + 1);
10856                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10857                         CHECK_CFG_ERROR;
10858
10859                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10860                         CHECK_CFG_ERROR;
10861
10862                         mono_save_token_info (cfg, image, token, cmethod);
10863
10864                         if (!mono_class_init (cmethod->klass))
10865                                 TYPE_LOAD_ERROR (cmethod->klass);
10866
10867                         context_used = mini_method_check_context_used (cfg, cmethod);
10868
10869                         if (mono_security_core_clr_enabled ())
10870                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10871
10872                         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)) {
10873                                 emit_class_init (cfg, cmethod->klass);
10874                                 CHECK_TYPELOAD (cmethod->klass);
10875                         }
10876
10877                         /*
10878                         if (cfg->gsharedvt) {
10879                                 if (mini_is_gsharedvt_variable_signature (sig))
10880                                         GSHAREDVT_FAILURE (*ip);
10881                         }
10882                         */
10883
10884                         n = fsig->param_count;
10885                         CHECK_STACK (n);
10886
10887                         /* 
10888                          * Generate smaller code for the common newobj <exception> instruction in
10889                          * argument checking code.
10890                          */
10891                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10892                                 is_exception_class (cmethod->klass) && n <= 2 &&
10893                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10894                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10895                                 MonoInst *iargs [3];
10896
10897                                 sp -= n;
10898
10899                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10900                                 switch (n) {
10901                                 case 0:
10902                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10903                                         break;
10904                                 case 1:
10905                                         iargs [1] = sp [0];
10906                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10907                                         break;
10908                                 case 2:
10909                                         iargs [1] = sp [0];
10910                                         iargs [2] = sp [1];
10911                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10912                                         break;
10913                                 default:
10914                                         g_assert_not_reached ();
10915                                 }
10916
10917                                 ip += 5;
10918                                 inline_costs += 5;
10919                                 break;
10920                         }
10921
10922                         /* move the args to allow room for 'this' in the first position */
10923                         while (n--) {
10924                                 --sp;
10925                                 sp [1] = sp [0];
10926                         }
10927
10928                         /* check_call_signature () requires sp[0] to be set */
10929                         this_ins.type = STACK_OBJ;
10930                         sp [0] = &this_ins;
10931                         if (check_call_signature (cfg, fsig, sp))
10932                                 UNVERIFIED;
10933
10934                         iargs [0] = NULL;
10935
10936                         if (mini_class_is_system_array (cmethod->klass)) {
10937                                 *sp = emit_get_rgctx_method (cfg, context_used,
10938                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10939
10940                                 /* Avoid varargs in the common case */
10941                                 if (fsig->param_count == 1)
10942                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10943                                 else if (fsig->param_count == 2)
10944                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10945                                 else if (fsig->param_count == 3)
10946                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10947                                 else if (fsig->param_count == 4)
10948                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10949                                 else
10950                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10951                         } else if (cmethod->string_ctor) {
10952                                 g_assert (!context_used);
10953                                 g_assert (!vtable_arg);
10954                                 /* we simply pass a null pointer */
10955                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10956                                 /* now call the string ctor */
10957                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10958                         } else {
10959                                 if (cmethod->klass->valuetype) {
10960                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10961                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10962                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10963
10964                                         alloc = NULL;
10965
10966                                         /* 
10967                                          * The code generated by mini_emit_virtual_call () expects
10968                                          * iargs [0] to be a boxed instance, but luckily the vcall
10969                                          * will be transformed into a normal call there.
10970                                          */
10971                                 } else if (context_used) {
10972                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10973                                         *sp = alloc;
10974                                 } else {
10975                                         MonoVTable *vtable = NULL;
10976
10977                                         if (!cfg->compile_aot)
10978                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10979                                         CHECK_TYPELOAD (cmethod->klass);
10980
10981                                         /*
10982                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10983                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10984                                          * As a workaround, we call class cctors before allocating objects.
10985                                          */
10986                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10987                                                 emit_class_init (cfg, cmethod->klass);
10988                                                 if (cfg->verbose_level > 2)
10989                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10990                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10991                                         }
10992
10993                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10994                                         *sp = alloc;
10995                                 }
10996                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10997
10998                                 if (alloc)
10999                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
11000
11001                                 /* Now call the actual ctor */
11002                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
11003                                 CHECK_CFG_EXCEPTION;
11004                         }
11005
11006                         if (alloc == NULL) {
11007                                 /* Valuetype */
11008                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
11009                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
11010                                 *sp++= ins;
11011                         } else {
11012                                 *sp++ = alloc;
11013                         }
11014                         
11015                         ip += 5;
11016                         inline_costs += 5;
11017                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
11018                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
11019                         break;
11020                 }
11021                 case CEE_CASTCLASS:
11022                 case CEE_ISINST: {
11023                         CHECK_STACK (1);
11024                         --sp;
11025                         CHECK_OPSIZE (5);
11026                         token = read32 (ip + 1);
11027                         klass = mini_get_class (method, token, generic_context);
11028                         CHECK_TYPELOAD (klass);
11029                         if (sp [0]->type != STACK_OBJ)
11030                                 UNVERIFIED;
11031
11032                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
11033                         ins->dreg = alloc_preg (cfg);
11034                         ins->sreg1 = (*sp)->dreg;
11035                         ins->klass = klass;
11036                         ins->type = STACK_OBJ;
11037                         MONO_ADD_INS (cfg->cbb, ins);
11038
11039                         CHECK_CFG_EXCEPTION;
11040                         *sp++ = ins;
11041                         ip += 5;
11042
11043                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
11044                         break;
11045                 }
11046                 case CEE_UNBOX_ANY: {
11047                         MonoInst *res, *addr;
11048
11049                         CHECK_STACK (1);
11050                         --sp;
11051                         CHECK_OPSIZE (5);
11052                         token = read32 (ip + 1);
11053                         klass = mini_get_class (method, token, generic_context);
11054                         CHECK_TYPELOAD (klass);
11055
11056                         mono_save_token_info (cfg, image, token, klass);
11057
11058                         context_used = mini_class_check_context_used (cfg, klass);
11059
11060                         if (mini_is_gsharedvt_klass (klass)) {
11061                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
11062                                 inline_costs += 2;
11063                         } else if (generic_class_is_reference_type (cfg, klass)) {
11064                                 if (MONO_INS_IS_PCONST_NULL (*sp)) {
11065                                         EMIT_NEW_PCONST (cfg, res, NULL);
11066                                         res->type = STACK_OBJ;
11067                                 } else {
11068                                         MONO_INST_NEW (cfg, res, OP_CASTCLASS);
11069                                         res->dreg = alloc_preg (cfg);
11070                                         res->sreg1 = (*sp)->dreg;
11071                                         res->klass = klass;
11072                                         res->type = STACK_OBJ;
11073                                         MONO_ADD_INS (cfg->cbb, res);
11074                                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
11075                                 }
11076                         } else if (mono_class_is_nullable (klass)) {
11077                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
11078                         } else {
11079                                 addr = handle_unbox (cfg, klass, sp, context_used);
11080                                 /* LDOBJ */
11081                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11082                                 res = ins;
11083                                 inline_costs += 2;
11084                         }
11085
11086                         *sp ++ = res;
11087                         ip += 5;
11088                         break;
11089                 }
11090                 case CEE_BOX: {
11091                         MonoInst *val;
11092                         MonoClass *enum_class;
11093                         MonoMethod *has_flag;
11094
11095                         CHECK_STACK (1);
11096                         --sp;
11097                         val = *sp;
11098                         CHECK_OPSIZE (5);
11099                         token = read32 (ip + 1);
11100                         klass = mini_get_class (method, token, generic_context);
11101                         CHECK_TYPELOAD (klass);
11102
11103                         mono_save_token_info (cfg, image, token, klass);
11104
11105                         context_used = mini_class_check_context_used (cfg, klass);
11106
11107                         if (generic_class_is_reference_type (cfg, klass)) {
11108                                 *sp++ = val;
11109                                 ip += 5;
11110                                 break;
11111                         }
11112
11113                         if (klass == mono_defaults.void_class)
11114                                 UNVERIFIED;
11115                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11116                                 UNVERIFIED;
11117                         /* frequent check in generic code: box (struct), brtrue */
11118
11119                         /*
11120                          * Look for:
11121                          *
11122                          *   <push int/long ptr>
11123                          *   <push int/long>
11124                          *   box MyFlags
11125                          *   constrained. MyFlags
11126                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11127                          *
11128                          * If we find this sequence and the operand types on box and constrained
11129                          * are equal, we can emit a specialized instruction sequence instead of
11130                          * the very slow HasFlag () call.
11131                          */
11132                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11133                             /* Cheap checks first. */
11134                             ip + 5 + 6 + 5 < end &&
11135                             ip [5] == CEE_PREFIX1 &&
11136                             ip [6] == CEE_CONSTRAINED_ &&
11137                             ip [11] == CEE_CALLVIRT &&
11138                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11139                             mono_class_is_enum (klass) &&
11140                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11141                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11142                             has_flag->klass == mono_defaults.enum_class &&
11143                             !strcmp (has_flag->name, "HasFlag") &&
11144                             has_flag->signature->hasthis &&
11145                             has_flag->signature->param_count == 1) {
11146                                 CHECK_TYPELOAD (enum_class);
11147
11148                                 if (enum_class == klass) {
11149                                         MonoInst *enum_this, *enum_flag;
11150
11151                                         ip += 5 + 6 + 5;
11152                                         --sp;
11153
11154                                         enum_this = sp [0];
11155                                         enum_flag = sp [1];
11156
11157                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11158                                         break;
11159                                 }
11160                         }
11161
11162                         // FIXME: LLVM can't handle the inconsistent bb linking
11163                         if (!mono_class_is_nullable (klass) &&
11164                                 !mini_is_gsharedvt_klass (klass) &&
11165                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11166                                 (ip [5] == CEE_BRTRUE || 
11167                                  ip [5] == CEE_BRTRUE_S ||
11168                                  ip [5] == CEE_BRFALSE ||
11169                                  ip [5] == CEE_BRFALSE_S)) {
11170                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11171                                 int dreg;
11172                                 MonoBasicBlock *true_bb, *false_bb;
11173
11174                                 ip += 5;
11175
11176                                 if (cfg->verbose_level > 3) {
11177                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11178                                         printf ("<box+brtrue opt>\n");
11179                                 }
11180
11181                                 switch (*ip) {
11182                                 case CEE_BRTRUE_S:
11183                                 case CEE_BRFALSE_S:
11184                                         CHECK_OPSIZE (2);
11185                                         ip++;
11186                                         target = ip + 1 + (signed char)(*ip);
11187                                         ip++;
11188                                         break;
11189                                 case CEE_BRTRUE:
11190                                 case CEE_BRFALSE:
11191                                         CHECK_OPSIZE (5);
11192                                         ip++;
11193                                         target = ip + 4 + (gint)(read32 (ip));
11194                                         ip += 4;
11195                                         break;
11196                                 default:
11197                                         g_assert_not_reached ();
11198                                 }
11199
11200                                 /* 
11201                                  * We need to link both bblocks, since it is needed for handling stack
11202                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11203                                  * Branching to only one of them would lead to inconsistencies, so
11204                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11205                                  */
11206                                 GET_BBLOCK (cfg, true_bb, target);
11207                                 GET_BBLOCK (cfg, false_bb, ip);
11208
11209                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11210                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11211
11212                                 if (sp != stack_start) {
11213                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11214                                         sp = stack_start;
11215                                         CHECK_UNVERIFIABLE (cfg);
11216                                 }
11217
11218                                 if (COMPILE_LLVM (cfg)) {
11219                                         dreg = alloc_ireg (cfg);
11220                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11221                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11222
11223                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11224                                 } else {
11225                                         /* The JIT can't eliminate the iconst+compare */
11226                                         MONO_INST_NEW (cfg, ins, OP_BR);
11227                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11228                                         MONO_ADD_INS (cfg->cbb, ins);
11229                                 }
11230
11231                                 start_new_bblock = 1;
11232                                 break;
11233                         }
11234
11235                         *sp++ = handle_box (cfg, val, klass, context_used);
11236
11237                         CHECK_CFG_EXCEPTION;
11238                         ip += 5;
11239                         inline_costs += 1;
11240                         break;
11241                 }
11242                 case CEE_UNBOX: {
11243                         CHECK_STACK (1);
11244                         --sp;
11245                         CHECK_OPSIZE (5);
11246                         token = read32 (ip + 1);
11247                         klass = mini_get_class (method, token, generic_context);
11248                         CHECK_TYPELOAD (klass);
11249
11250                         mono_save_token_info (cfg, image, token, klass);
11251
11252                         context_used = mini_class_check_context_used (cfg, klass);
11253
11254                         if (mono_class_is_nullable (klass)) {
11255                                 MonoInst *val;
11256
11257                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11258                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11259
11260                                 *sp++= ins;
11261                         } else {
11262                                 ins = handle_unbox (cfg, klass, sp, context_used);
11263                                 *sp++ = ins;
11264                         }
11265                         ip += 5;
11266                         inline_costs += 2;
11267                         break;
11268                 }
11269                 case CEE_LDFLD:
11270                 case CEE_LDFLDA:
11271                 case CEE_STFLD:
11272                 case CEE_LDSFLD:
11273                 case CEE_LDSFLDA:
11274                 case CEE_STSFLD: {
11275                         MonoClassField *field;
11276 #ifndef DISABLE_REMOTING
11277                         int costs;
11278 #endif
11279                         guint foffset;
11280                         gboolean is_instance;
11281                         int op;
11282                         gpointer addr = NULL;
11283                         gboolean is_special_static;
11284                         MonoType *ftype;
11285                         MonoInst *store_val = NULL;
11286                         MonoInst *thread_ins;
11287
11288                         op = *ip;
11289                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11290                         if (is_instance) {
11291                                 if (op == CEE_STFLD) {
11292                                         CHECK_STACK (2);
11293                                         sp -= 2;
11294                                         store_val = sp [1];
11295                                 } else {
11296                                         CHECK_STACK (1);
11297                                         --sp;
11298                                 }
11299                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11300                                         UNVERIFIED;
11301                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11302                                         UNVERIFIED;
11303                         } else {
11304                                 if (op == CEE_STSFLD) {
11305                                         CHECK_STACK (1);
11306                                         sp--;
11307                                         store_val = sp [0];
11308                                 }
11309                         }
11310
11311                         CHECK_OPSIZE (5);
11312                         token = read32 (ip + 1);
11313                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11314                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11315                                 klass = field->parent;
11316                         }
11317                         else {
11318                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11319                                 CHECK_CFG_ERROR;
11320                         }
11321                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11322                                 FIELD_ACCESS_FAILURE (method, field);
11323                         mono_class_init (klass);
11324
11325                         /* if the class is Critical then transparent code cannot access it's fields */
11326                         if (!is_instance && mono_security_core_clr_enabled ())
11327                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11328
11329                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11330                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11331                         if (mono_security_core_clr_enabled ())
11332                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11333                         */
11334
11335                         ftype = mono_field_get_type (field);
11336
11337                         /*
11338                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11339                          * the static case.
11340                          */
11341                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11342                                 switch (op) {
11343                                 case CEE_LDFLD:
11344                                         op = CEE_LDSFLD;
11345                                         break;
11346                                 case CEE_STFLD:
11347                                         op = CEE_STSFLD;
11348                                         break;
11349                                 case CEE_LDFLDA:
11350                                         op = CEE_LDSFLDA;
11351                                         break;
11352                                 default:
11353                                         g_assert_not_reached ();
11354                                 }
11355                                 is_instance = FALSE;
11356                         }
11357
11358                         context_used = mini_class_check_context_used (cfg, klass);
11359
11360                         /* INSTANCE CASE */
11361
11362                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11363                         if (op == CEE_STFLD) {
11364                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11365                                         UNVERIFIED;
11366 #ifndef DISABLE_REMOTING
11367                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11368                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11369                                         MonoInst *iargs [5];
11370
11371                                         GSHAREDVT_FAILURE (op);
11372
11373                                         iargs [0] = sp [0];
11374                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11375                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11376                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11377                                                     field->offset);
11378                                         iargs [4] = sp [1];
11379
11380                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11381                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11382                                                                                            iargs, ip, cfg->real_offset, TRUE);
11383                                                 CHECK_CFG_EXCEPTION;
11384                                                 g_assert (costs > 0);
11385                                                       
11386                                                 cfg->real_offset += 5;
11387
11388                                                 inline_costs += costs;
11389                                         } else {
11390                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11391                                         }
11392                                 } else
11393 #endif
11394                                 {
11395                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
11396
11397                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11398
11399                                         if (ins_flag & MONO_INST_VOLATILE) {
11400                                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11401                                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11402                                         }
11403
11404                                         if (mini_is_gsharedvt_klass (klass)) {
11405                                                 MonoInst *offset_ins;
11406
11407                                                 context_used = mini_class_check_context_used (cfg, klass);
11408
11409                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11410                                                 /* The value is offset by 1 */
11411                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11412                                                 dreg = alloc_ireg_mp (cfg);
11413                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11414                                                 wbarrier_ptr_ins = ins;
11415                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11416                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11417                                         } else {
11418                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11419                                         }
11420                                         if (sp [0]->opcode != OP_LDADDR)
11421                                                 store->flags |= MONO_INST_FAULT;
11422
11423                                         if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
11424                                                 if (mini_is_gsharedvt_klass (klass)) {
11425                                                         g_assert (wbarrier_ptr_ins);
11426                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
11427                                                 } else {
11428                                                         /* insert call to write barrier */
11429                                                         MonoInst *ptr;
11430                                                         int dreg;
11431
11432                                                         dreg = alloc_ireg_mp (cfg);
11433                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11434                                                         emit_write_barrier (cfg, ptr, sp [1]);
11435                                                 }
11436                                         }
11437
11438                                         store->flags |= ins_flag;
11439                                 }
11440                                 ins_flag = 0;
11441                                 ip += 5;
11442                                 break;
11443                         }
11444
11445 #ifndef DISABLE_REMOTING
11446                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11447                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11448                                 MonoInst *iargs [4];
11449
11450                                 GSHAREDVT_FAILURE (op);
11451
11452                                 iargs [0] = sp [0];
11453                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11454                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11455                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11456                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11457                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11458                                                                                    iargs, ip, cfg->real_offset, TRUE);
11459                                         CHECK_CFG_EXCEPTION;
11460                                         g_assert (costs > 0);
11461                                                       
11462                                         cfg->real_offset += 5;
11463
11464                                         *sp++ = iargs [0];
11465
11466                                         inline_costs += costs;
11467                                 } else {
11468                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11469                                         *sp++ = ins;
11470                                 }
11471                         } else 
11472 #endif
11473                         if (is_instance) {
11474                                 if (sp [0]->type == STACK_VTYPE) {
11475                                         MonoInst *var;
11476
11477                                         /* Have to compute the address of the variable */
11478
11479                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11480                                         if (!var)
11481                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11482                                         else
11483                                                 g_assert (var->klass == klass);
11484                                         
11485                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11486                                         sp [0] = ins;
11487                                 }
11488
11489                                 if (op == CEE_LDFLDA) {
11490                                         if (sp [0]->type == STACK_OBJ) {
11491                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11492                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11493                                         }
11494
11495                                         dreg = alloc_ireg_mp (cfg);
11496
11497                                         if (mini_is_gsharedvt_klass (klass)) {
11498                                                 MonoInst *offset_ins;
11499
11500                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11501                                                 /* The value is offset by 1 */
11502                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11503                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11504                                         } else {
11505                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11506                                         }
11507                                         ins->klass = mono_class_from_mono_type (field->type);
11508                                         ins->type = STACK_MP;
11509                                         *sp++ = ins;
11510                                 } else {
11511                                         MonoInst *load;
11512
11513                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11514
11515                                         if (sp [0]->opcode == OP_LDADDR && klass->simd_type && cfg->opt & MONO_OPT_SIMD) {
11516                                                 ins = mono_emit_simd_field_load (cfg, field, sp [0]);
11517                                                 if (ins) {
11518                                                         *sp++ = ins;
11519                                                         ins_flag = 0;
11520                                                         ip += 5;
11521                                                         break;
11522                                                 }
11523                                         }
11524
11525                                         if (mini_is_gsharedvt_klass (klass)) {
11526                                                 MonoInst *offset_ins;
11527
11528                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11529                                                 /* The value is offset by 1 */
11530                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11531                                                 dreg = alloc_ireg_mp (cfg);
11532                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11533                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11534                                         } else {
11535                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11536                                         }
11537                                         load->flags |= ins_flag;
11538                                         if (sp [0]->opcode != OP_LDADDR)
11539                                                 load->flags |= MONO_INST_FAULT;
11540                                         *sp++ = load;
11541                                 }
11542                         }
11543
11544                         if (is_instance) {
11545                                 ins_flag = 0;
11546                                 ip += 5;
11547                                 break;
11548                         }
11549
11550                         /* STATIC CASE */
11551                         context_used = mini_class_check_context_used (cfg, klass);
11552
11553                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
11554                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
11555                                 CHECK_CFG_ERROR;
11556                         }
11557
11558                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11559                          * to be called here.
11560                          */
11561                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11562                                 mono_class_vtable (cfg->domain, klass);
11563                                 CHECK_TYPELOAD (klass);
11564                         }
11565                         mono_domain_lock (cfg->domain);
11566                         if (cfg->domain->special_static_fields)
11567                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11568                         mono_domain_unlock (cfg->domain);
11569
11570                         is_special_static = mono_class_field_is_special_static (field);
11571
11572                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11573                                 thread_ins = mono_get_thread_intrinsic (cfg);
11574                         else
11575                                 thread_ins = NULL;
11576
11577                         /* Generate IR to compute the field address */
11578                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11579                                 /*
11580                                  * Fast access to TLS data
11581                                  * Inline version of get_thread_static_data () in
11582                                  * threads.c.
11583                                  */
11584                                 guint32 offset;
11585                                 int idx, static_data_reg, array_reg, dreg;
11586
11587                                 GSHAREDVT_FAILURE (op);
11588
11589                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11590                                 static_data_reg = alloc_ireg (cfg);
11591                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11592
11593                                 if (cfg->compile_aot) {
11594                                         int offset_reg, offset2_reg, idx_reg;
11595
11596                                         /* For TLS variables, this will return the TLS offset */
11597                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11598                                         offset_reg = ins->dreg;
11599                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11600                                         idx_reg = alloc_ireg (cfg);
11601                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11602                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11603                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11604                                         array_reg = alloc_ireg (cfg);
11605                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11606                                         offset2_reg = alloc_ireg (cfg);
11607                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11608                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11609                                         dreg = alloc_ireg (cfg);
11610                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11611                                 } else {
11612                                         offset = (gsize)addr & 0x7fffffff;
11613                                         idx = offset & 0x3f;
11614
11615                                         array_reg = alloc_ireg (cfg);
11616                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11617                                         dreg = alloc_ireg (cfg);
11618                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11619                                 }
11620                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11621                                         (cfg->compile_aot && is_special_static) ||
11622                                         (context_used && is_special_static)) {
11623                                 MonoInst *iargs [2];
11624
11625                                 g_assert (field->parent);
11626                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11627                                 if (context_used) {
11628                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11629                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11630                                 } else {
11631                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11632                                 }
11633                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11634                         } else if (context_used) {
11635                                 MonoInst *static_data;
11636
11637                                 /*
11638                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11639                                         method->klass->name_space, method->klass->name, method->name,
11640                                         depth, field->offset);
11641                                 */
11642
11643                                 if (mono_class_needs_cctor_run (klass, method))
11644                                         emit_class_init (cfg, klass);
11645
11646                                 /*
11647                                  * The pointer we're computing here is
11648                                  *
11649                                  *   super_info.static_data + field->offset
11650                                  */
11651                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11652                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11653
11654                                 if (mini_is_gsharedvt_klass (klass)) {
11655                                         MonoInst *offset_ins;
11656
11657                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11658                                         /* The value is offset by 1 */
11659                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11660                                         dreg = alloc_ireg_mp (cfg);
11661                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11662                                 } else if (field->offset == 0) {
11663                                         ins = static_data;
11664                                 } else {
11665                                         int addr_reg = mono_alloc_preg (cfg);
11666                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11667                                 }
11668                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11669                                 MonoInst *iargs [2];
11670
11671                                 g_assert (field->parent);
11672                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11673                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11674                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11675                         } else {
11676                                 MonoVTable *vtable = NULL;
11677
11678                                 if (!cfg->compile_aot)
11679                                         vtable = mono_class_vtable (cfg->domain, klass);
11680                                 CHECK_TYPELOAD (klass);
11681
11682                                 if (!addr) {
11683                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11684                                                 if (!(g_slist_find (class_inits, klass))) {
11685                                                         emit_class_init (cfg, klass);
11686                                                         if (cfg->verbose_level > 2)
11687                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11688                                                         class_inits = g_slist_prepend (class_inits, klass);
11689                                                 }
11690                                         } else {
11691                                                 if (cfg->run_cctors) {
11692                                                         /* This makes so that inline cannot trigger */
11693                                                         /* .cctors: too many apps depend on them */
11694                                                         /* running with a specific order... */
11695                                                         g_assert (vtable);
11696                                                         if (! vtable->initialized)
11697                                                                 INLINE_FAILURE ("class init");
11698                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
11699                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11700                                                                 goto exception_exit;
11701                                                         }
11702                                                 }
11703                                         }
11704                                         if (cfg->compile_aot)
11705                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11706                                         else {
11707                                                 g_assert (vtable);
11708                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11709                                                 g_assert (addr);
11710                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11711                                         }
11712                                 } else {
11713                                         MonoInst *iargs [1];
11714                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11715                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11716                                 }
11717                         }
11718
11719                         /* Generate IR to do the actual load/store operation */
11720
11721                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11722                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11723                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11724                         }
11725
11726                         if (op == CEE_LDSFLDA) {
11727                                 ins->klass = mono_class_from_mono_type (ftype);
11728                                 ins->type = STACK_PTR;
11729                                 *sp++ = ins;
11730                         } else if (op == CEE_STSFLD) {
11731                                 MonoInst *store;
11732
11733                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11734                                 store->flags |= ins_flag;
11735                         } else {
11736                                 gboolean is_const = FALSE;
11737                                 MonoVTable *vtable = NULL;
11738                                 gpointer addr = NULL;
11739
11740                                 if (!context_used) {
11741                                         vtable = mono_class_vtable (cfg->domain, klass);
11742                                         CHECK_TYPELOAD (klass);
11743                                 }
11744                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11745                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11746                                         int ro_type = ftype->type;
11747                                         if (!addr)
11748                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11749                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11750                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11751                                         }
11752
11753                                         GSHAREDVT_FAILURE (op);
11754
11755                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11756                                         is_const = TRUE;
11757                                         switch (ro_type) {
11758                                         case MONO_TYPE_BOOLEAN:
11759                                         case MONO_TYPE_U1:
11760                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11761                                                 sp++;
11762                                                 break;
11763                                         case MONO_TYPE_I1:
11764                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11765                                                 sp++;
11766                                                 break;                                          
11767                                         case MONO_TYPE_CHAR:
11768                                         case MONO_TYPE_U2:
11769                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11770                                                 sp++;
11771                                                 break;
11772                                         case MONO_TYPE_I2:
11773                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11774                                                 sp++;
11775                                                 break;
11776                                                 break;
11777                                         case MONO_TYPE_I4:
11778                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11779                                                 sp++;
11780                                                 break;                                          
11781                                         case MONO_TYPE_U4:
11782                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11783                                                 sp++;
11784                                                 break;
11785                                         case MONO_TYPE_I:
11786                                         case MONO_TYPE_U:
11787                                         case MONO_TYPE_PTR:
11788                                         case MONO_TYPE_FNPTR:
11789                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11790                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11791                                                 sp++;
11792                                                 break;
11793                                         case MONO_TYPE_STRING:
11794                                         case MONO_TYPE_OBJECT:
11795                                         case MONO_TYPE_CLASS:
11796                                         case MONO_TYPE_SZARRAY:
11797                                         case MONO_TYPE_ARRAY:
11798                                                 if (!mono_gc_is_moving ()) {
11799                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11800                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11801                                                         sp++;
11802                                                 } else {
11803                                                         is_const = FALSE;
11804                                                 }
11805                                                 break;
11806                                         case MONO_TYPE_I8:
11807                                         case MONO_TYPE_U8:
11808                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11809                                                 sp++;
11810                                                 break;
11811                                         case MONO_TYPE_R4:
11812                                         case MONO_TYPE_R8:
11813                                         case MONO_TYPE_VALUETYPE:
11814                                         default:
11815                                                 is_const = FALSE;
11816                                                 break;
11817                                         }
11818                                 }
11819
11820                                 if (!is_const) {
11821                                         MonoInst *load;
11822
11823                                         CHECK_STACK_OVF (1);
11824
11825                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11826                                         load->flags |= ins_flag;
11827                                         ins_flag = 0;
11828                                         *sp++ = load;
11829                                 }
11830                         }
11831
11832                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11833                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11834                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11835                         }
11836
11837                         ins_flag = 0;
11838                         ip += 5;
11839                         break;
11840                 }
11841                 case CEE_STOBJ:
11842                         CHECK_STACK (2);
11843                         sp -= 2;
11844                         CHECK_OPSIZE (5);
11845                         token = read32 (ip + 1);
11846                         klass = mini_get_class (method, token, generic_context);
11847                         CHECK_TYPELOAD (klass);
11848                         if (ins_flag & MONO_INST_VOLATILE) {
11849                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11850                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11851                         }
11852                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11853                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11854                         ins->flags |= ins_flag;
11855                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11856                                 generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
11857                                 /* insert call to write barrier */
11858                                 emit_write_barrier (cfg, sp [0], sp [1]);
11859                         }
11860                         ins_flag = 0;
11861                         ip += 5;
11862                         inline_costs += 1;
11863                         break;
11864
11865                         /*
11866                          * Array opcodes
11867                          */
11868                 case CEE_NEWARR: {
11869                         MonoInst *len_ins;
11870                         const char *data_ptr;
11871                         int data_size = 0;
11872                         guint32 field_token;
11873
11874                         CHECK_STACK (1);
11875                         --sp;
11876
11877                         CHECK_OPSIZE (5);
11878                         token = read32 (ip + 1);
11879
11880                         klass = mini_get_class (method, token, generic_context);
11881                         CHECK_TYPELOAD (klass);
11882
11883                         context_used = mini_class_check_context_used (cfg, klass);
11884
11885                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11886                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11887                                 ins->sreg1 = sp [0]->dreg;
11888                                 ins->type = STACK_I4;
11889                                 ins->dreg = alloc_ireg (cfg);
11890                                 MONO_ADD_INS (cfg->cbb, ins);
11891                                 *sp = mono_decompose_opcode (cfg, ins);
11892                         }
11893
11894                         if (context_used) {
11895                                 MonoInst *args [3];
11896                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11897                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11898
11899                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11900
11901                                 /* vtable */
11902                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11903                                         array_class, MONO_RGCTX_INFO_VTABLE);
11904                                 /* array len */
11905                                 args [1] = sp [0];
11906
11907                                 if (managed_alloc)
11908                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11909                                 else
11910                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11911                         } else {
11912                                 if (cfg->opt & MONO_OPT_SHARED) {
11913                                         /* Decompose now to avoid problems with references to the domainvar */
11914                                         MonoInst *iargs [3];
11915
11916                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11917                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11918                                         iargs [2] = sp [0];
11919
11920                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11921                                 } else {
11922                                         /* Decompose later since it is needed by abcrem */
11923                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11924                                         mono_class_vtable (cfg->domain, array_type);
11925                                         CHECK_TYPELOAD (array_type);
11926
11927                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11928                                         ins->dreg = alloc_ireg_ref (cfg);
11929                                         ins->sreg1 = sp [0]->dreg;
11930                                         ins->inst_newa_class = klass;
11931                                         ins->type = STACK_OBJ;
11932                                         ins->klass = array_type;
11933                                         MONO_ADD_INS (cfg->cbb, ins);
11934                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11935                                         cfg->cbb->has_array_access = TRUE;
11936
11937                                         /* Needed so mono_emit_load_get_addr () gets called */
11938                                         mono_get_got_var (cfg);
11939                                 }
11940                         }
11941
11942                         len_ins = sp [0];
11943                         ip += 5;
11944                         *sp++ = ins;
11945                         inline_costs += 1;
11946
11947                         /* 
11948                          * we inline/optimize the initialization sequence if possible.
11949                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11950                          * for small sizes open code the memcpy
11951                          * ensure the rva field is big enough
11952                          */
11953                         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))) {
11954                                 MonoMethod *memcpy_method = get_memcpy_method ();
11955                                 MonoInst *iargs [3];
11956                                 int add_reg = alloc_ireg_mp (cfg);
11957
11958                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11959                                 if (cfg->compile_aot) {
11960                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11961                                 } else {
11962                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11963                                 }
11964                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11965                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11966                                 ip += 11;
11967                         }
11968
11969                         break;
11970                 }
11971                 case CEE_LDLEN:
11972                         CHECK_STACK (1);
11973                         --sp;
11974                         if (sp [0]->type != STACK_OBJ)
11975                                 UNVERIFIED;
11976
11977                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11978                         ins->dreg = alloc_preg (cfg);
11979                         ins->sreg1 = sp [0]->dreg;
11980                         ins->type = STACK_I4;
11981                         /* This flag will be inherited by the decomposition */
11982                         ins->flags |= MONO_INST_FAULT;
11983                         MONO_ADD_INS (cfg->cbb, ins);
11984                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11985                         cfg->cbb->has_array_access = TRUE;
11986                         ip ++;
11987                         *sp++ = ins;
11988                         break;
11989                 case CEE_LDELEMA:
11990                         CHECK_STACK (2);
11991                         sp -= 2;
11992                         CHECK_OPSIZE (5);
11993                         if (sp [0]->type != STACK_OBJ)
11994                                 UNVERIFIED;
11995
11996                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11997
11998                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11999                         CHECK_TYPELOAD (klass);
12000                         /* we need to make sure that this array is exactly the type it needs
12001                          * to be for correctness. the wrappers are lax with their usage
12002                          * so we need to ignore them here
12003                          */
12004                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
12005                                 MonoClass *array_class = mono_array_class_get (klass, 1);
12006                                 mini_emit_check_array_type (cfg, sp [0], array_class);
12007                                 CHECK_TYPELOAD (array_class);
12008                         }
12009
12010                         readonly = FALSE;
12011                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12012                         *sp++ = ins;
12013                         ip += 5;
12014                         break;
12015                 case CEE_LDELEM:
12016                 case CEE_LDELEM_I1:
12017                 case CEE_LDELEM_U1:
12018                 case CEE_LDELEM_I2:
12019                 case CEE_LDELEM_U2:
12020                 case CEE_LDELEM_I4:
12021                 case CEE_LDELEM_U4:
12022                 case CEE_LDELEM_I8:
12023                 case CEE_LDELEM_I:
12024                 case CEE_LDELEM_R4:
12025                 case CEE_LDELEM_R8:
12026                 case CEE_LDELEM_REF: {
12027                         MonoInst *addr;
12028
12029                         CHECK_STACK (2);
12030                         sp -= 2;
12031
12032                         if (*ip == CEE_LDELEM) {
12033                                 CHECK_OPSIZE (5);
12034                                 token = read32 (ip + 1);
12035                                 klass = mini_get_class (method, token, generic_context);
12036                                 CHECK_TYPELOAD (klass);
12037                                 mono_class_init (klass);
12038                         }
12039                         else
12040                                 klass = array_access_to_klass (*ip);
12041
12042                         if (sp [0]->type != STACK_OBJ)
12043                                 UNVERIFIED;
12044
12045                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12046
12047                         if (mini_is_gsharedvt_variable_klass (klass)) {
12048                                 // FIXME-VT: OP_ICONST optimization
12049                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12050                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12051                                 ins->opcode = OP_LOADV_MEMBASE;
12052                         } else if (sp [1]->opcode == OP_ICONST) {
12053                                 int array_reg = sp [0]->dreg;
12054                                 int index_reg = sp [1]->dreg;
12055                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
12056
12057                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
12058                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
12059
12060                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
12061                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
12062                         } else {
12063                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12064                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12065                         }
12066                         *sp++ = ins;
12067                         if (*ip == CEE_LDELEM)
12068                                 ip += 5;
12069                         else
12070                                 ++ip;
12071                         break;
12072                 }
12073                 case CEE_STELEM_I:
12074                 case CEE_STELEM_I1:
12075                 case CEE_STELEM_I2:
12076                 case CEE_STELEM_I4:
12077                 case CEE_STELEM_I8:
12078                 case CEE_STELEM_R4:
12079                 case CEE_STELEM_R8:
12080                 case CEE_STELEM_REF:
12081                 case CEE_STELEM: {
12082                         CHECK_STACK (3);
12083                         sp -= 3;
12084
12085                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12086
12087                         if (*ip == CEE_STELEM) {
12088                                 CHECK_OPSIZE (5);
12089                                 token = read32 (ip + 1);
12090                                 klass = mini_get_class (method, token, generic_context);
12091                                 CHECK_TYPELOAD (klass);
12092                                 mono_class_init (klass);
12093                         }
12094                         else
12095                                 klass = array_access_to_klass (*ip);
12096
12097                         if (sp [0]->type != STACK_OBJ)
12098                                 UNVERIFIED;
12099
12100                         emit_array_store (cfg, klass, sp, TRUE);
12101
12102                         if (*ip == CEE_STELEM)
12103                                 ip += 5;
12104                         else
12105                                 ++ip;
12106                         inline_costs += 1;
12107                         break;
12108                 }
12109                 case CEE_CKFINITE: {
12110                         CHECK_STACK (1);
12111                         --sp;
12112
12113                         if (cfg->llvm_only) {
12114                                 MonoInst *iargs [1];
12115
12116                                 iargs [0] = sp [0];
12117                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12118                         } else  {
12119                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12120                                 ins->sreg1 = sp [0]->dreg;
12121                                 ins->dreg = alloc_freg (cfg);
12122                                 ins->type = STACK_R8;
12123                                 MONO_ADD_INS (cfg->cbb, ins);
12124
12125                                 *sp++ = mono_decompose_opcode (cfg, ins);
12126                         }
12127
12128                         ++ip;
12129                         break;
12130                 }
12131                 case CEE_REFANYVAL: {
12132                         MonoInst *src_var, *src;
12133
12134                         int klass_reg = alloc_preg (cfg);
12135                         int dreg = alloc_preg (cfg);
12136
12137                         GSHAREDVT_FAILURE (*ip);
12138
12139                         CHECK_STACK (1);
12140                         MONO_INST_NEW (cfg, ins, *ip);
12141                         --sp;
12142                         CHECK_OPSIZE (5);
12143                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12144                         CHECK_TYPELOAD (klass);
12145
12146                         context_used = mini_class_check_context_used (cfg, klass);
12147
12148                         // FIXME:
12149                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12150                         if (!src_var)
12151                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12152                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12153                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12154
12155                         if (context_used) {
12156                                 MonoInst *klass_ins;
12157
12158                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12159                                                 klass, MONO_RGCTX_INFO_KLASS);
12160
12161                                 // FIXME:
12162                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12163                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12164                         } else {
12165                                 mini_emit_class_check (cfg, klass_reg, klass);
12166                         }
12167                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12168                         ins->type = STACK_MP;
12169                         ins->klass = klass;
12170                         *sp++ = ins;
12171                         ip += 5;
12172                         break;
12173                 }
12174                 case CEE_MKREFANY: {
12175                         MonoInst *loc, *addr;
12176
12177                         GSHAREDVT_FAILURE (*ip);
12178
12179                         CHECK_STACK (1);
12180                         MONO_INST_NEW (cfg, ins, *ip);
12181                         --sp;
12182                         CHECK_OPSIZE (5);
12183                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12184                         CHECK_TYPELOAD (klass);
12185
12186                         context_used = mini_class_check_context_used (cfg, klass);
12187
12188                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12189                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12190
12191                         if (context_used) {
12192                                 MonoInst *const_ins;
12193                                 int type_reg = alloc_preg (cfg);
12194
12195                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12196                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12197                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12198                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12199                         } else {
12200                                 int const_reg = alloc_preg (cfg);
12201                                 int type_reg = alloc_preg (cfg);
12202
12203                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12204                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12205                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12206                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12207                         }
12208                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12209
12210                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12211                         ins->type = STACK_VTYPE;
12212                         ins->klass = mono_defaults.typed_reference_class;
12213                         *sp++ = ins;
12214                         ip += 5;
12215                         break;
12216                 }
12217                 case CEE_LDTOKEN: {
12218                         gpointer handle;
12219                         MonoClass *handle_class;
12220
12221                         CHECK_STACK_OVF (1);
12222
12223                         CHECK_OPSIZE (5);
12224                         n = read32 (ip + 1);
12225
12226                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12227                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12228                                 handle = mono_method_get_wrapper_data (method, n);
12229                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12230                                 if (handle_class == mono_defaults.typehandle_class)
12231                                         handle = &((MonoClass*)handle)->byval_arg;
12232                         }
12233                         else {
12234                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12235                                 CHECK_CFG_ERROR;
12236                         }
12237                         if (!handle)
12238                                 LOAD_ERROR;
12239                         mono_class_init (handle_class);
12240                         if (cfg->gshared) {
12241                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12242                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12243                                         /* This case handles ldtoken
12244                                            of an open type, like for
12245                                            typeof(Gen<>). */
12246                                         context_used = 0;
12247                                 } else if (handle_class == mono_defaults.typehandle_class) {
12248                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12249                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12250                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12251                                 else if (handle_class == mono_defaults.methodhandle_class)
12252                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12253                                 else
12254                                         g_assert_not_reached ();
12255                         }
12256
12257                         if ((cfg->opt & MONO_OPT_SHARED) &&
12258                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12259                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12260                                 MonoInst *addr, *vtvar, *iargs [3];
12261                                 int method_context_used;
12262
12263                                 method_context_used = mini_method_check_context_used (cfg, method);
12264
12265                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12266
12267                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12268                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12269                                 if (method_context_used) {
12270                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12271                                                 method, MONO_RGCTX_INFO_METHOD);
12272                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12273                                 } else {
12274                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12275                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12276                                 }
12277                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12278
12279                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12280
12281                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12282                         } else {
12283                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12284                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12285                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12286                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12287                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12288                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12289
12290                                         mono_class_init (tclass);
12291                                         if (context_used) {
12292                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12293                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12294                                         } else if (cfg->compile_aot) {
12295                                                 if (method->wrapper_type) {
12296                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12297                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12298                                                                 /* Special case for static synchronized wrappers */
12299                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12300                                                         } else {
12301                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12302                                                                 /* FIXME: n is not a normal token */
12303                                                                 DISABLE_AOT (cfg);
12304                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12305                                                         }
12306                                                 } else {
12307                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12308                                                 }
12309                                         } else {
12310                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
12311                                                 CHECK_CFG_ERROR;
12312                                                 EMIT_NEW_PCONST (cfg, ins, rt);
12313                                         }
12314                                         ins->type = STACK_OBJ;
12315                                         ins->klass = cmethod->klass;
12316                                         ip += 5;
12317                                 } else {
12318                                         MonoInst *addr, *vtvar;
12319
12320                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12321
12322                                         if (context_used) {
12323                                                 if (handle_class == mono_defaults.typehandle_class) {
12324                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12325                                                                         mono_class_from_mono_type ((MonoType *)handle),
12326                                                                         MONO_RGCTX_INFO_TYPE);
12327                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12328                                                         ins = emit_get_rgctx_method (cfg, context_used,
12329                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12330                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12331                                                         ins = emit_get_rgctx_field (cfg, context_used,
12332                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12333                                                 } else {
12334                                                         g_assert_not_reached ();
12335                                                 }
12336                                         } else if (cfg->compile_aot) {
12337                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12338                                         } else {
12339                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12340                                         }
12341                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12342                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12343                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12344                                 }
12345                         }
12346
12347                         *sp++ = ins;
12348                         ip += 5;
12349                         break;
12350                 }
12351                 case CEE_THROW:
12352                         CHECK_STACK (1);
12353                         if (sp [-1]->type != STACK_OBJ)
12354                                 UNVERIFIED;
12355
12356                         MONO_INST_NEW (cfg, ins, OP_THROW);
12357                         --sp;
12358                         ins->sreg1 = sp [0]->dreg;
12359                         ip++;
12360                         cfg->cbb->out_of_line = TRUE;
12361                         MONO_ADD_INS (cfg->cbb, ins);
12362                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12363                         MONO_ADD_INS (cfg->cbb, ins);
12364                         sp = stack_start;
12365                         
12366                         link_bblock (cfg, cfg->cbb, end_bblock);
12367                         start_new_bblock = 1;
12368                         /* This can complicate code generation for llvm since the return value might not be defined */
12369                         if (COMPILE_LLVM (cfg))
12370                                 INLINE_FAILURE ("throw");
12371                         break;
12372                 case CEE_ENDFINALLY:
12373                         if (!ip_in_finally_clause (cfg, ip - header->code))
12374                                 UNVERIFIED;
12375                         /* mono_save_seq_point_info () depends on this */
12376                         if (sp != stack_start)
12377                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12378                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12379                         MONO_ADD_INS (cfg->cbb, ins);
12380                         ip++;
12381                         start_new_bblock = 1;
12382
12383                         /*
12384                          * Control will leave the method so empty the stack, otherwise
12385                          * the next basic block will start with a nonempty stack.
12386                          */
12387                         while (sp != stack_start) {
12388                                 sp--;
12389                         }
12390                         break;
12391                 case CEE_LEAVE:
12392                 case CEE_LEAVE_S: {
12393                         GList *handlers;
12394
12395                         if (*ip == CEE_LEAVE) {
12396                                 CHECK_OPSIZE (5);
12397                                 target = ip + 5 + (gint32)read32(ip + 1);
12398                         } else {
12399                                 CHECK_OPSIZE (2);
12400                                 target = ip + 2 + (signed char)(ip [1]);
12401                         }
12402
12403                         /* empty the stack */
12404                         while (sp != stack_start) {
12405                                 sp--;
12406                         }
12407
12408                         /* 
12409                          * If this leave statement is in a catch block, check for a
12410                          * pending exception, and rethrow it if necessary.
12411                          * We avoid doing this in runtime invoke wrappers, since those are called
12412                          * by native code which excepts the wrapper to catch all exceptions.
12413                          */
12414                         for (i = 0; i < header->num_clauses; ++i) {
12415                                 MonoExceptionClause *clause = &header->clauses [i];
12416
12417                                 /* 
12418                                  * Use <= in the final comparison to handle clauses with multiple
12419                                  * leave statements, like in bug #78024.
12420                                  * The ordering of the exception clauses guarantees that we find the
12421                                  * innermost clause.
12422                                  */
12423                                 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) {
12424                                         MonoInst *exc_ins;
12425                                         MonoBasicBlock *dont_throw;
12426
12427                                         /*
12428                                           MonoInst *load;
12429
12430                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12431                                         */
12432
12433                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12434
12435                                         NEW_BBLOCK (cfg, dont_throw);
12436
12437                                         /*
12438                                          * Currently, we always rethrow the abort exception, despite the 
12439                                          * fact that this is not correct. See thread6.cs for an example. 
12440                                          * But propagating the abort exception is more important than 
12441                                          * getting the sematics right.
12442                                          */
12443                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12444                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12445                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12446
12447                                         MONO_START_BB (cfg, dont_throw);
12448                                 }
12449                         }
12450
12451 #ifdef ENABLE_LLVM
12452                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12453 #endif
12454
12455                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12456                                 GList *tmp;
12457                                 MonoExceptionClause *clause;
12458
12459                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12460                                         clause = (MonoExceptionClause *)tmp->data;
12461                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12462                                         g_assert (tblock);
12463                                         link_bblock (cfg, cfg->cbb, tblock);
12464                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12465                                         ins->inst_target_bb = tblock;
12466                                         ins->inst_eh_block = clause;
12467                                         MONO_ADD_INS (cfg->cbb, ins);
12468                                         cfg->cbb->has_call_handler = 1;
12469                                         if (COMPILE_LLVM (cfg)) {
12470                                                 MonoBasicBlock *target_bb;
12471
12472                                                 /* 
12473                                                  * Link the finally bblock with the target, since it will
12474                                                  * conceptually branch there.
12475                                                  */
12476                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
12477                                                 GET_BBLOCK (cfg, target_bb, target);
12478                                                 link_bblock (cfg, tblock, target_bb);
12479                                         }
12480                                 }
12481                                 g_list_free (handlers);
12482                         } 
12483
12484                         MONO_INST_NEW (cfg, ins, OP_BR);
12485                         MONO_ADD_INS (cfg->cbb, ins);
12486                         GET_BBLOCK (cfg, tblock, target);
12487                         link_bblock (cfg, cfg->cbb, tblock);
12488                         ins->inst_target_bb = tblock;
12489
12490                         start_new_bblock = 1;
12491
12492                         if (*ip == CEE_LEAVE)
12493                                 ip += 5;
12494                         else
12495                                 ip += 2;
12496
12497                         break;
12498                 }
12499
12500                         /*
12501                          * Mono specific opcodes
12502                          */
12503                 case MONO_CUSTOM_PREFIX: {
12504
12505                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12506
12507                         CHECK_OPSIZE (2);
12508                         switch (ip [1]) {
12509                         case CEE_MONO_ICALL: {
12510                                 gpointer func;
12511                                 MonoJitICallInfo *info;
12512
12513                                 token = read32 (ip + 2);
12514                                 func = mono_method_get_wrapper_data (method, token);
12515                                 info = mono_find_jit_icall_by_addr (func);
12516                                 if (!info)
12517                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12518                                 g_assert (info);
12519
12520                                 CHECK_STACK (info->sig->param_count);
12521                                 sp -= info->sig->param_count;
12522
12523                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12524                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12525                                         *sp++ = ins;
12526
12527                                 ip += 6;
12528                                 inline_costs += 10 * num_calls++;
12529
12530                                 break;
12531                         }
12532                         case CEE_MONO_LDPTR_CARD_TABLE:
12533                         case CEE_MONO_LDPTR_NURSERY_START:
12534                         case CEE_MONO_LDPTR_NURSERY_BITS:
12535                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12536                                 CHECK_STACK_OVF (1);
12537
12538                                 switch (ip [1]) {
12539                                         case CEE_MONO_LDPTR_CARD_TABLE:
12540                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12541                                                 break;
12542                                         case CEE_MONO_LDPTR_NURSERY_START:
12543                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12544                                                 break;
12545                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12546                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12547                                                 break;
12548                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12549                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12550                                                 break;
12551                                 }
12552
12553                                 *sp++ = ins;
12554                                 ip += 2;
12555                                 inline_costs += 10 * num_calls++;
12556                                 break;
12557                         }
12558                         case CEE_MONO_LDPTR: {
12559                                 gpointer ptr;
12560
12561                                 CHECK_STACK_OVF (1);
12562                                 CHECK_OPSIZE (6);
12563                                 token = read32 (ip + 2);
12564
12565                                 ptr = mono_method_get_wrapper_data (method, token);
12566                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12567                                 *sp++ = ins;
12568                                 ip += 6;
12569                                 inline_costs += 10 * num_calls++;
12570                                 /* Can't embed random pointers into AOT code */
12571                                 DISABLE_AOT (cfg);
12572                                 break;
12573                         }
12574                         case CEE_MONO_JIT_ICALL_ADDR: {
12575                                 MonoJitICallInfo *callinfo;
12576                                 gpointer ptr;
12577
12578                                 CHECK_STACK_OVF (1);
12579                                 CHECK_OPSIZE (6);
12580                                 token = read32 (ip + 2);
12581
12582                                 ptr = mono_method_get_wrapper_data (method, token);
12583                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12584                                 g_assert (callinfo);
12585                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12586                                 *sp++ = ins;
12587                                 ip += 6;
12588                                 inline_costs += 10 * num_calls++;
12589                                 break;
12590                         }
12591                         case CEE_MONO_ICALL_ADDR: {
12592                                 MonoMethod *cmethod;
12593                                 gpointer ptr;
12594
12595                                 CHECK_STACK_OVF (1);
12596                                 CHECK_OPSIZE (6);
12597                                 token = read32 (ip + 2);
12598
12599                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12600
12601                                 if (cfg->compile_aot) {
12602                                         if (cfg->direct_pinvoke && ip + 6 < end && (ip [6] == CEE_POP)) {
12603                                                 /*
12604                                                  * This is generated by emit_native_wrapper () to resolve the pinvoke address
12605                                                  * before the call, its not needed when using direct pinvoke.
12606                                                  * This is not an optimization, but its used to avoid looking up pinvokes
12607                                                  * on platforms which don't support dlopen ().
12608                                                  */
12609                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12610                                         } else {
12611                                                 EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12612                                         }
12613                                 } else {
12614                                         ptr = mono_lookup_internal_call (cmethod);
12615                                         g_assert (ptr);
12616                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12617                                 }
12618                                 *sp++ = ins;
12619                                 ip += 6;
12620                                 break;
12621                         }
12622                         case CEE_MONO_VTADDR: {
12623                                 MonoInst *src_var, *src;
12624
12625                                 CHECK_STACK (1);
12626                                 --sp;
12627
12628                                 // FIXME:
12629                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12630                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12631                                 *sp++ = src;
12632                                 ip += 2;
12633                                 break;
12634                         }
12635                         case CEE_MONO_NEWOBJ: {
12636                                 MonoInst *iargs [2];
12637
12638                                 CHECK_STACK_OVF (1);
12639                                 CHECK_OPSIZE (6);
12640                                 token = read32 (ip + 2);
12641                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12642                                 mono_class_init (klass);
12643                                 NEW_DOMAINCONST (cfg, iargs [0]);
12644                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12645                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12646                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12647                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
12648                                 ip += 6;
12649                                 inline_costs += 10 * num_calls++;
12650                                 break;
12651                         }
12652                         case CEE_MONO_OBJADDR:
12653                                 CHECK_STACK (1);
12654                                 --sp;
12655                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12656                                 ins->dreg = alloc_ireg_mp (cfg);
12657                                 ins->sreg1 = sp [0]->dreg;
12658                                 ins->type = STACK_MP;
12659                                 MONO_ADD_INS (cfg->cbb, ins);
12660                                 *sp++ = ins;
12661                                 ip += 2;
12662                                 break;
12663                         case CEE_MONO_LDNATIVEOBJ:
12664                                 /*
12665                                  * Similar to LDOBJ, but instead load the unmanaged 
12666                                  * representation of the vtype to the stack.
12667                                  */
12668                                 CHECK_STACK (1);
12669                                 CHECK_OPSIZE (6);
12670                                 --sp;
12671                                 token = read32 (ip + 2);
12672                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12673                                 g_assert (klass->valuetype);
12674                                 mono_class_init (klass);
12675
12676                                 {
12677                                         MonoInst *src, *dest, *temp;
12678
12679                                         src = sp [0];
12680                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12681                                         temp->backend.is_pinvoke = 1;
12682                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12683                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12684
12685                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12686                                         dest->type = STACK_VTYPE;
12687                                         dest->klass = klass;
12688
12689                                         *sp ++ = dest;
12690                                         ip += 6;
12691                                 }
12692                                 break;
12693                         case CEE_MONO_RETOBJ: {
12694                                 /*
12695                                  * Same as RET, but return the native representation of a vtype
12696                                  * to the caller.
12697                                  */
12698                                 g_assert (cfg->ret);
12699                                 g_assert (mono_method_signature (method)->pinvoke); 
12700                                 CHECK_STACK (1);
12701                                 --sp;
12702                                 
12703                                 CHECK_OPSIZE (6);
12704                                 token = read32 (ip + 2);    
12705                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12706
12707                                 if (!cfg->vret_addr) {
12708                                         g_assert (cfg->ret_var_is_local);
12709
12710                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12711                                 } else {
12712                                         EMIT_NEW_RETLOADA (cfg, ins);
12713                                 }
12714                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12715                                 
12716                                 if (sp != stack_start)
12717                                         UNVERIFIED;
12718                                 
12719                                 MONO_INST_NEW (cfg, ins, OP_BR);
12720                                 ins->inst_target_bb = end_bblock;
12721                                 MONO_ADD_INS (cfg->cbb, ins);
12722                                 link_bblock (cfg, cfg->cbb, end_bblock);
12723                                 start_new_bblock = 1;
12724                                 ip += 6;
12725                                 break;
12726                         }
12727                         case CEE_MONO_CISINST:
12728                         case CEE_MONO_CCASTCLASS: {
12729                                 int token;
12730                                 CHECK_STACK (1);
12731                                 --sp;
12732                                 CHECK_OPSIZE (6);
12733                                 token = read32 (ip + 2);
12734                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12735                                 if (ip [1] == CEE_MONO_CISINST)
12736                                         ins = handle_cisinst (cfg, klass, sp [0]);
12737                                 else
12738                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12739                                 *sp++ = ins;
12740                                 ip += 6;
12741                                 break;
12742                         }
12743                         case CEE_MONO_SAVE_LMF:
12744                         case CEE_MONO_RESTORE_LMF:
12745                                 ip += 2;
12746                                 break;
12747                         case CEE_MONO_CLASSCONST:
12748                                 CHECK_STACK_OVF (1);
12749                                 CHECK_OPSIZE (6);
12750                                 token = read32 (ip + 2);
12751                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12752                                 *sp++ = ins;
12753                                 ip += 6;
12754                                 inline_costs += 10 * num_calls++;
12755                                 break;
12756                         case CEE_MONO_NOT_TAKEN:
12757                                 cfg->cbb->out_of_line = TRUE;
12758                                 ip += 2;
12759                                 break;
12760                         case CEE_MONO_TLS: {
12761                                 MonoTlsKey key;
12762
12763                                 CHECK_STACK_OVF (1);
12764                                 CHECK_OPSIZE (6);
12765                                 key = (MonoTlsKey)read32 (ip + 2);
12766                                 g_assert (key < TLS_KEY_NUM);
12767
12768                                 ins = mono_create_tls_get (cfg, key);
12769                                 if (!ins) {
12770                                         if (cfg->compile_aot) {
12771                                                 DISABLE_AOT (cfg);
12772                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12773                                                 ins->dreg = alloc_preg (cfg);
12774                                                 ins->type = STACK_PTR;
12775                                         } else {
12776                                                 g_assert_not_reached ();
12777                                         }
12778                                 }
12779                                 ins->type = STACK_PTR;
12780                                 MONO_ADD_INS (cfg->cbb, ins);
12781                                 *sp++ = ins;
12782                                 ip += 6;
12783                                 break;
12784                         }
12785                         case CEE_MONO_DYN_CALL: {
12786                                 MonoCallInst *call;
12787
12788                                 /* It would be easier to call a trampoline, but that would put an
12789                                  * extra frame on the stack, confusing exception handling. So
12790                                  * implement it inline using an opcode for now.
12791                                  */
12792
12793                                 if (!cfg->dyn_call_var) {
12794                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12795                                         /* prevent it from being register allocated */
12796                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12797                                 }
12798
12799                                 /* Has to use a call inst since it local regalloc expects it */
12800                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12801                                 ins = (MonoInst*)call;
12802                                 sp -= 2;
12803                                 ins->sreg1 = sp [0]->dreg;
12804                                 ins->sreg2 = sp [1]->dreg;
12805                                 MONO_ADD_INS (cfg->cbb, ins);
12806
12807                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12808
12809                                 ip += 2;
12810                                 inline_costs += 10 * num_calls++;
12811
12812                                 break;
12813                         }
12814                         case CEE_MONO_MEMORY_BARRIER: {
12815                                 CHECK_OPSIZE (6);
12816                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12817                                 ip += 6;
12818                                 break;
12819                         }
12820                         case CEE_MONO_ATOMIC_STORE_I4: {
12821                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
12822
12823                                 CHECK_OPSIZE (6);
12824                                 CHECK_STACK (2);
12825                                 sp -= 2;
12826
12827                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
12828                                 ins->dreg = sp [0]->dreg;
12829                                 ins->sreg1 = sp [1]->dreg;
12830                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
12831                                 MONO_ADD_INS (cfg->cbb, ins);
12832
12833                                 ip += 6;
12834                                 break;
12835                         }
12836                         case CEE_MONO_JIT_ATTACH: {
12837                                 MonoInst *args [16], *domain_ins;
12838                                 MonoInst *ad_ins, *jit_tls_ins;
12839                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12840
12841                                 g_assert (!mono_threads_is_coop_enabled ());
12842
12843                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12844
12845                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12846                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12847
12848                                 ad_ins = mono_get_domain_intrinsic (cfg);
12849                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12850
12851                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12852                                         NEW_BBLOCK (cfg, next_bb);
12853                                         NEW_BBLOCK (cfg, call_bb);
12854
12855                                         if (cfg->compile_aot) {
12856                                                 /* AOT code is only used in the root domain */
12857                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12858                                         } else {
12859                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12860                                         }
12861                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12862                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12863                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12864
12865                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12866                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12867                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12868
12869                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12870                                         MONO_START_BB (cfg, call_bb);
12871                                 }
12872
12873                                 /* AOT code is only used in the root domain */
12874                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12875                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12876                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12877
12878                                 if (next_bb)
12879                                         MONO_START_BB (cfg, next_bb);
12880
12881
12882                                 ip += 2;
12883                                 break;
12884                         }
12885                         case CEE_MONO_JIT_DETACH: {
12886                                 MonoInst *args [16];
12887
12888                                 /* Restore the original domain */
12889                                 dreg = alloc_ireg (cfg);
12890                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12891                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12892                                 ip += 2;
12893                                 break;
12894                         }
12895                         case CEE_MONO_CALLI_EXTRA_ARG: {
12896                                 MonoInst *addr;
12897                                 MonoMethodSignature *fsig;
12898                                 MonoInst *arg;
12899
12900                                 /*
12901                                  * This is the same as CEE_CALLI, but passes an additional argument
12902                                  * to the called method in llvmonly mode.
12903                                  * This is only used by delegate invoke wrappers to call the
12904                                  * actual delegate method.
12905                                  */
12906                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12907
12908                                 CHECK_OPSIZE (6);
12909                                 token = read32 (ip + 2);
12910
12911                                 ins = NULL;
12912
12913                                 cmethod = NULL;
12914                                 CHECK_STACK (1);
12915                                 --sp;
12916                                 addr = *sp;
12917                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12918                                 CHECK_CFG_ERROR;
12919
12920                                 if (cfg->llvm_only)
12921                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12922
12923                                 n = fsig->param_count + fsig->hasthis + 1;
12924
12925                                 CHECK_STACK (n);
12926
12927                                 sp -= n;
12928                                 arg = sp [n - 1];
12929
12930                                 if (cfg->llvm_only) {
12931                                         /*
12932                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12933                                          * cconv. This is set by mono_init_delegate ().
12934                                          */
12935                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12936                                                 MonoInst *callee = addr;
12937                                                 MonoInst *call, *localloc_ins;
12938                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12939                                                 int low_bit_reg = alloc_preg (cfg);
12940
12941                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12942                                                 NEW_BBLOCK (cfg, end_bb);
12943
12944                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12945                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12946                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12947
12948                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12949                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12950                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12951                                                 /*
12952                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12953                                                  */
12954                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12955                                                 ins->dreg = alloc_preg (cfg);
12956                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12957                                                 MONO_ADD_INS (cfg->cbb, ins);
12958                                                 localloc_ins = ins;
12959                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12960                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12961                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12962
12963                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12964                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12965
12966                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12967                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12968                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12969                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12970                                                 ins->dreg = call->dreg;
12971
12972                                                 MONO_START_BB (cfg, end_bb);
12973                                         } else {
12974                                                 /* Caller uses a normal calling conv */
12975
12976                                                 MonoInst *callee = addr;
12977                                                 MonoInst *call, *localloc_ins;
12978                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12979                                                 int low_bit_reg = alloc_preg (cfg);
12980
12981                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12982                                                 NEW_BBLOCK (cfg, end_bb);
12983
12984                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12985                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12986                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12987
12988                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12989                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12990                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12991                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12992                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12993                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12994                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12995                                                 MONO_ADD_INS (cfg->cbb, addr);
12996                                                 /*
12997                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12998                                                  */
12999                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
13000                                                 ins->dreg = alloc_preg (cfg);
13001                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
13002                                                 MONO_ADD_INS (cfg->cbb, ins);
13003                                                 localloc_ins = ins;
13004                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13005                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
13006                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
13007
13008                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
13009                                                 ins->dreg = call->dreg;
13010                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
13011
13012                                                 MONO_START_BB (cfg, end_bb);
13013                                         }
13014                                 } else {
13015                                         /* Same as CEE_CALLI */
13016                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
13017                                                 /*
13018                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
13019                                                  */
13020                                                 MonoInst *callee = addr;
13021
13022                                                 addr = emit_get_rgctx_sig (cfg, context_used,
13023                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
13024                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
13025                                         } else {
13026                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
13027                                         }
13028                                 }
13029
13030                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
13031                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
13032
13033                                 CHECK_CFG_EXCEPTION;
13034
13035                                 ip += 6;
13036                                 ins_flag = 0;
13037                                 constrained_class = NULL;
13038                                 break;
13039                         }
13040                         case CEE_MONO_LDDOMAIN:
13041                                 CHECK_STACK_OVF (1);
13042                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
13043                                 ip += 2;
13044                                 *sp++ = ins;
13045                                 break;
13046                         case CEE_MONO_GET_LAST_ERROR:
13047                                 CHECK_OPSIZE (2);
13048                                 CHECK_STACK_OVF (1);
13049
13050                                 MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
13051                                 ins->dreg = alloc_dreg (cfg, STACK_I4);
13052                                 ins->type = STACK_I4;
13053                                 MONO_ADD_INS (cfg->cbb, ins);
13054
13055                                 ip += 2;
13056                                 *sp++ = ins;
13057                                 break;
13058                         default:
13059                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
13060                                 break;
13061                         }
13062                         break;
13063                 }
13064
13065                 case CEE_PREFIX1: {
13066                         CHECK_OPSIZE (2);
13067                         switch (ip [1]) {
13068                         case CEE_ARGLIST: {
13069                                 /* somewhat similar to LDTOKEN */
13070                                 MonoInst *addr, *vtvar;
13071                                 CHECK_STACK_OVF (1);
13072                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
13073
13074                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
13075                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
13076
13077                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
13078                                 ins->type = STACK_VTYPE;
13079                                 ins->klass = mono_defaults.argumenthandle_class;
13080                                 *sp++ = ins;
13081                                 ip += 2;
13082                                 break;
13083                         }
13084                         case CEE_CEQ:
13085                         case CEE_CGT:
13086                         case CEE_CGT_UN:
13087                         case CEE_CLT:
13088                         case CEE_CLT_UN: {
13089                                 MonoInst *cmp, *arg1, *arg2;
13090
13091                                 CHECK_STACK (2);
13092                                 sp -= 2;
13093                                 arg1 = sp [0];
13094                                 arg2 = sp [1];
13095
13096                                 /*
13097                                  * The following transforms:
13098                                  *    CEE_CEQ    into OP_CEQ
13099                                  *    CEE_CGT    into OP_CGT
13100                                  *    CEE_CGT_UN into OP_CGT_UN
13101                                  *    CEE_CLT    into OP_CLT
13102                                  *    CEE_CLT_UN into OP_CLT_UN
13103                                  */
13104                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
13105
13106                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
13107                                 cmp->sreg1 = arg1->dreg;
13108                                 cmp->sreg2 = arg2->dreg;
13109                                 type_from_op (cfg, cmp, arg1, arg2);
13110                                 CHECK_TYPE (cmp);
13111                                 add_widen_op (cfg, cmp, &arg1, &arg2);
13112                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
13113                                         cmp->opcode = OP_LCOMPARE;
13114                                 else if (arg1->type == STACK_R4)
13115                                         cmp->opcode = OP_RCOMPARE;
13116                                 else if (arg1->type == STACK_R8)
13117                                         cmp->opcode = OP_FCOMPARE;
13118                                 else
13119                                         cmp->opcode = OP_ICOMPARE;
13120                                 MONO_ADD_INS (cfg->cbb, cmp);
13121                                 ins->type = STACK_I4;
13122                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
13123                                 type_from_op (cfg, ins, arg1, arg2);
13124
13125                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13126                                         /*
13127                                          * The backends expect the fceq opcodes to do the
13128                                          * comparison too.
13129                                          */
13130                                         ins->sreg1 = cmp->sreg1;
13131                                         ins->sreg2 = cmp->sreg2;
13132                                         NULLIFY_INS (cmp);
13133                                 }
13134                                 MONO_ADD_INS (cfg->cbb, ins);
13135                                 *sp++ = ins;
13136                                 ip += 2;
13137                                 break;
13138                         }
13139                         case CEE_LDFTN: {
13140                                 MonoInst *argconst;
13141                                 MonoMethod *cil_method;
13142
13143                                 CHECK_STACK_OVF (1);
13144                                 CHECK_OPSIZE (6);
13145                                 n = read32 (ip + 2);
13146                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13147                                 CHECK_CFG_ERROR;
13148
13149                                 mono_class_init (cmethod->klass);
13150
13151                                 mono_save_token_info (cfg, image, n, cmethod);
13152
13153                                 context_used = mini_method_check_context_used (cfg, cmethod);
13154
13155                                 cil_method = cmethod;
13156                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13157                                         emit_method_access_failure (cfg, method, cil_method);
13158
13159                                 if (mono_security_core_clr_enabled ())
13160                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13161
13162                                 /* 
13163                                  * Optimize the common case of ldftn+delegate creation
13164                                  */
13165                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13166                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13167                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13168                                                 MonoInst *target_ins, *handle_ins;
13169                                                 MonoMethod *invoke;
13170                                                 int invoke_context_used;
13171
13172                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13173                                                 if (!invoke || !mono_method_signature (invoke))
13174                                                         LOAD_ERROR;
13175
13176                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13177
13178                                                 target_ins = sp [-1];
13179
13180                                                 if (mono_security_core_clr_enabled ())
13181                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13182
13183                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13184                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13185                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13186                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13187                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13188                                                         }
13189                                                 }
13190
13191                                                 /* FIXME: SGEN support */
13192                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13193                                                         ip += 6;
13194                                                         if (cfg->verbose_level > 3)
13195                                                                 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));
13196                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13197                                                                 sp --;
13198                                                                 *sp = handle_ins;
13199                                                                 CHECK_CFG_EXCEPTION;
13200                                                                 ip += 5;
13201                                                                 sp ++;
13202                                                                 break;
13203                                                         }
13204                                                         ip -= 6;
13205                                                 }
13206                                         }
13207                                 }
13208
13209                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13210                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13211                                 *sp++ = ins;
13212                                 
13213                                 ip += 6;
13214                                 inline_costs += 10 * num_calls++;
13215                                 break;
13216                         }
13217                         case CEE_LDVIRTFTN: {
13218                                 MonoInst *args [2];
13219
13220                                 CHECK_STACK (1);
13221                                 CHECK_OPSIZE (6);
13222                                 n = read32 (ip + 2);
13223                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13224                                 CHECK_CFG_ERROR;
13225
13226                                 mono_class_init (cmethod->klass);
13227  
13228                                 context_used = mini_method_check_context_used (cfg, cmethod);
13229
13230                                 if (mono_security_core_clr_enabled ())
13231                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13232
13233                                 /*
13234                                  * Optimize the common case of ldvirtftn+delegate creation
13235                                  */
13236                                 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)) {
13237                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13238                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13239                                                 MonoInst *target_ins, *handle_ins;
13240                                                 MonoMethod *invoke;
13241                                                 int invoke_context_used;
13242                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13243
13244                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13245                                                 if (!invoke || !mono_method_signature (invoke))
13246                                                         LOAD_ERROR;
13247
13248                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13249
13250                                                 target_ins = sp [-1];
13251
13252                                                 if (mono_security_core_clr_enabled ())
13253                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13254
13255                                                 /* FIXME: SGEN support */
13256                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13257                                                         ip += 6;
13258                                                         if (cfg->verbose_level > 3)
13259                                                                 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));
13260                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13261                                                                 sp -= 2;
13262                                                                 *sp = handle_ins;
13263                                                                 CHECK_CFG_EXCEPTION;
13264                                                                 ip += 5;
13265                                                                 sp ++;
13266                                                                 break;
13267                                                         }
13268                                                         ip -= 6;
13269                                                 }
13270                                         }
13271                                 }
13272
13273                                 --sp;
13274                                 args [0] = *sp;
13275
13276                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13277                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13278
13279                                 if (context_used)
13280                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13281                                 else
13282                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13283
13284                                 ip += 6;
13285                                 inline_costs += 10 * num_calls++;
13286                                 break;
13287                         }
13288                         case CEE_LDARG:
13289                                 CHECK_STACK_OVF (1);
13290                                 CHECK_OPSIZE (4);
13291                                 n = read16 (ip + 2);
13292                                 CHECK_ARG (n);
13293                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13294                                 *sp++ = ins;
13295                                 ip += 4;
13296                                 break;
13297                         case CEE_LDARGA:
13298                                 CHECK_STACK_OVF (1);
13299                                 CHECK_OPSIZE (4);
13300                                 n = read16 (ip + 2);
13301                                 CHECK_ARG (n);
13302                                 NEW_ARGLOADA (cfg, ins, n);
13303                                 MONO_ADD_INS (cfg->cbb, ins);
13304                                 *sp++ = ins;
13305                                 ip += 4;
13306                                 break;
13307                         case CEE_STARG:
13308                                 CHECK_STACK (1);
13309                                 --sp;
13310                                 CHECK_OPSIZE (4);
13311                                 n = read16 (ip + 2);
13312                                 CHECK_ARG (n);
13313                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13314                                         UNVERIFIED;
13315                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13316                                 ip += 4;
13317                                 break;
13318                         case CEE_LDLOC:
13319                                 CHECK_STACK_OVF (1);
13320                                 CHECK_OPSIZE (4);
13321                                 n = read16 (ip + 2);
13322                                 CHECK_LOCAL (n);
13323                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13324                                 *sp++ = ins;
13325                                 ip += 4;
13326                                 break;
13327                         case CEE_LDLOCA: {
13328                                 unsigned char *tmp_ip;
13329                                 CHECK_STACK_OVF (1);
13330                                 CHECK_OPSIZE (4);
13331                                 n = read16 (ip + 2);
13332                                 CHECK_LOCAL (n);
13333
13334                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13335                                         ip = tmp_ip;
13336                                         inline_costs += 1;
13337                                         break;
13338                                 }                       
13339                                 
13340                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13341                                 *sp++ = ins;
13342                                 ip += 4;
13343                                 break;
13344                         }
13345                         case CEE_STLOC:
13346                                 CHECK_STACK (1);
13347                                 --sp;
13348                                 CHECK_OPSIZE (4);
13349                                 n = read16 (ip + 2);
13350                                 CHECK_LOCAL (n);
13351                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13352                                         UNVERIFIED;
13353                                 emit_stloc_ir (cfg, sp, header, n);
13354                                 ip += 4;
13355                                 inline_costs += 1;
13356                                 break;
13357                         case CEE_LOCALLOC: {
13358                                 CHECK_STACK (1);
13359                                 MonoBasicBlock *non_zero_bb, *end_bb;
13360                                 int alloc_ptr = alloc_preg (cfg);
13361                                 --sp;
13362                                 if (sp != stack_start) 
13363                                         UNVERIFIED;
13364                                 if (cfg->method != method) 
13365                                         /* 
13366                                          * Inlining this into a loop in a parent could lead to 
13367                                          * stack overflows which is different behavior than the
13368                                          * non-inlined case, thus disable inlining in this case.
13369                                          */
13370                                         INLINE_FAILURE("localloc");
13371
13372                                 NEW_BBLOCK (cfg, non_zero_bb);
13373                                 NEW_BBLOCK (cfg, end_bb);
13374
13375                                 /* if size != zero */
13376                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
13377                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
13378
13379                                 //size is zero, so result is NULL
13380                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
13381                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
13382
13383                                 MONO_START_BB (cfg, non_zero_bb);
13384                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13385                                 ins->dreg = alloc_ptr;
13386                                 ins->sreg1 = sp [0]->dreg;
13387                                 ins->type = STACK_PTR;
13388                                 MONO_ADD_INS (cfg->cbb, ins);
13389
13390                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13391                                 if (init_locals)
13392                                         ins->flags |= MONO_INST_INIT;
13393
13394                                 MONO_START_BB (cfg, end_bb);
13395                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
13396                                 ins->type = STACK_PTR;
13397
13398                                 *sp++ = ins;
13399                                 ip += 2;
13400                                 break;
13401                         }
13402                         case CEE_ENDFILTER: {
13403                                 MonoExceptionClause *clause, *nearest;
13404                                 int cc;
13405
13406                                 CHECK_STACK (1);
13407                                 --sp;
13408                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13409                                         UNVERIFIED;
13410                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13411                                 ins->sreg1 = (*sp)->dreg;
13412                                 MONO_ADD_INS (cfg->cbb, ins);
13413                                 start_new_bblock = 1;
13414                                 ip += 2;
13415
13416                                 nearest = NULL;
13417                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13418                                         clause = &header->clauses [cc];
13419                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13420                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13421                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13422                                                 nearest = clause;
13423                                 }
13424                                 g_assert (nearest);
13425                                 if ((ip - header->code) != nearest->handler_offset)
13426                                         UNVERIFIED;
13427
13428                                 break;
13429                         }
13430                         case CEE_UNALIGNED_:
13431                                 ins_flag |= MONO_INST_UNALIGNED;
13432                                 /* FIXME: record alignment? we can assume 1 for now */
13433                                 CHECK_OPSIZE (3);
13434                                 ip += 3;
13435                                 break;
13436                         case CEE_VOLATILE_:
13437                                 ins_flag |= MONO_INST_VOLATILE;
13438                                 ip += 2;
13439                                 break;
13440                         case CEE_TAIL_:
13441                                 ins_flag   |= MONO_INST_TAILCALL;
13442                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13443                                 /* Can't inline tail calls at this time */
13444                                 inline_costs += 100000;
13445                                 ip += 2;
13446                                 break;
13447                         case CEE_INITOBJ:
13448                                 CHECK_STACK (1);
13449                                 --sp;
13450                                 CHECK_OPSIZE (6);
13451                                 token = read32 (ip + 2);
13452                                 klass = mini_get_class (method, token, generic_context);
13453                                 CHECK_TYPELOAD (klass);
13454                                 if (generic_class_is_reference_type (cfg, klass))
13455                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13456                                 else
13457                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13458                                 ip += 6;
13459                                 inline_costs += 1;
13460                                 break;
13461                         case CEE_CONSTRAINED_:
13462                                 CHECK_OPSIZE (6);
13463                                 token = read32 (ip + 2);
13464                                 constrained_class = mini_get_class (method, token, generic_context);
13465                                 CHECK_TYPELOAD (constrained_class);
13466                                 ip += 6;
13467                                 break;
13468                         case CEE_CPBLK:
13469                         case CEE_INITBLK: {
13470                                 MonoInst *iargs [3];
13471                                 CHECK_STACK (3);
13472                                 sp -= 3;
13473
13474                                 /* Skip optimized paths for volatile operations. */
13475                                 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)) {
13476                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13477                                 } 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)) {
13478                                         /* emit_memset only works when val == 0 */
13479                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13480                                 } else {
13481                                         MonoInst *call;
13482                                         iargs [0] = sp [0];
13483                                         iargs [1] = sp [1];
13484                                         iargs [2] = sp [2];
13485                                         if (ip [1] == CEE_CPBLK) {
13486                                                 /*
13487                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13488                                                  * and release barriers for cpblk. It is technically both a load and
13489                                                  * store operation, so it seems like that's the sensible thing to do.
13490                                                  *
13491                                                  * FIXME: We emit full barriers on both sides of the operation for
13492                                                  * simplicity. We should have a separate atomic memcpy method instead.
13493                                                  */
13494                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13495
13496                                                 if (ins_flag & MONO_INST_VOLATILE)
13497                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13498
13499                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13500                                                 call->flags |= ins_flag;
13501
13502                                                 if (ins_flag & MONO_INST_VOLATILE)
13503                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13504                                         } else {
13505                                                 MonoMethod *memset_method = get_memset_method ();
13506                                                 if (ins_flag & MONO_INST_VOLATILE) {
13507                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13508                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13509                                                 }
13510                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13511                                                 call->flags |= ins_flag;
13512                                         }
13513                                 }
13514                                 ip += 2;
13515                                 ins_flag = 0;
13516                                 inline_costs += 1;
13517                                 break;
13518                         }
13519                         case CEE_NO_:
13520                                 CHECK_OPSIZE (3);
13521                                 if (ip [2] & 0x1)
13522                                         ins_flag |= MONO_INST_NOTYPECHECK;
13523                                 if (ip [2] & 0x2)
13524                                         ins_flag |= MONO_INST_NORANGECHECK;
13525                                 /* we ignore the no-nullcheck for now since we
13526                                  * really do it explicitly only when doing callvirt->call
13527                                  */
13528                                 ip += 3;
13529                                 break;
13530                         case CEE_RETHROW: {
13531                                 MonoInst *load;
13532                                 int handler_offset = -1;
13533
13534                                 for (i = 0; i < header->num_clauses; ++i) {
13535                                         MonoExceptionClause *clause = &header->clauses [i];
13536                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13537                                                 handler_offset = clause->handler_offset;
13538                                                 break;
13539                                         }
13540                                 }
13541
13542                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13543
13544                                 if (handler_offset == -1)
13545                                         UNVERIFIED;
13546
13547                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13548                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13549                                 ins->sreg1 = load->dreg;
13550                                 MONO_ADD_INS (cfg->cbb, ins);
13551
13552                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13553                                 MONO_ADD_INS (cfg->cbb, ins);
13554
13555                                 sp = stack_start;
13556                                 link_bblock (cfg, cfg->cbb, end_bblock);
13557                                 start_new_bblock = 1;
13558                                 ip += 2;
13559                                 break;
13560                         }
13561                         case CEE_SIZEOF: {
13562                                 guint32 val;
13563                                 int ialign;
13564
13565                                 CHECK_STACK_OVF (1);
13566                                 CHECK_OPSIZE (6);
13567                                 token = read32 (ip + 2);
13568                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13569                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13570                                         CHECK_CFG_ERROR;
13571
13572                                         val = mono_type_size (type, &ialign);
13573                                 } else {
13574                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13575                                         CHECK_TYPELOAD (klass);
13576
13577                                         val = mono_type_size (&klass->byval_arg, &ialign);
13578
13579                                         if (mini_is_gsharedvt_klass (klass))
13580                                                 GSHAREDVT_FAILURE (*ip);
13581                                 }
13582                                 EMIT_NEW_ICONST (cfg, ins, val);
13583                                 *sp++= ins;
13584                                 ip += 6;
13585                                 break;
13586                         }
13587                         case CEE_REFANYTYPE: {
13588                                 MonoInst *src_var, *src;
13589
13590                                 GSHAREDVT_FAILURE (*ip);
13591
13592                                 CHECK_STACK (1);
13593                                 --sp;
13594
13595                                 // FIXME:
13596                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13597                                 if (!src_var)
13598                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13599                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13600                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13601                                 *sp++ = ins;
13602                                 ip += 2;
13603                                 break;
13604                         }
13605                         case CEE_READONLY_:
13606                                 readonly = TRUE;
13607                                 ip += 2;
13608                                 break;
13609
13610                         case CEE_UNUSED56:
13611                         case CEE_UNUSED57:
13612                         case CEE_UNUSED70:
13613                         case CEE_UNUSED:
13614                         case CEE_UNUSED99:
13615                                 UNVERIFIED;
13616                                 
13617                         default:
13618                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13619                                 UNVERIFIED;
13620                         }
13621                         break;
13622                 }
13623                 case CEE_UNUSED58:
13624                 case CEE_UNUSED1:
13625                         UNVERIFIED;
13626
13627                 default:
13628                         g_warning ("opcode 0x%02x not handled", *ip);
13629                         UNVERIFIED;
13630                 }
13631         }
13632         if (start_new_bblock != 1)
13633                 UNVERIFIED;
13634
13635         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13636         if (cfg->cbb->next_bb) {
13637                 /* This could already be set because of inlining, #693905 */
13638                 MonoBasicBlock *bb = cfg->cbb;
13639
13640                 while (bb->next_bb)
13641                         bb = bb->next_bb;
13642                 bb->next_bb = end_bblock;
13643         } else {
13644                 cfg->cbb->next_bb = end_bblock;
13645         }
13646
13647         if (cfg->method == method && cfg->domainvar) {
13648                 MonoInst *store;
13649                 MonoInst *get_domain;
13650
13651                 cfg->cbb = init_localsbb;
13652
13653                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13654                         MONO_ADD_INS (cfg->cbb, get_domain);
13655                 } else {
13656                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13657                 }
13658                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13659                 MONO_ADD_INS (cfg->cbb, store);
13660         }
13661
13662 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13663         if (cfg->compile_aot)
13664                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13665                 mono_get_got_var (cfg);
13666 #endif
13667
13668         if (cfg->method == method && cfg->got_var)
13669                 mono_emit_load_got_addr (cfg);
13670
13671         if (init_localsbb) {
13672                 cfg->cbb = init_localsbb;
13673                 cfg->ip = NULL;
13674                 for (i = 0; i < header->num_locals; ++i) {
13675                         emit_init_local (cfg, i, header->locals [i], init_locals);
13676                 }
13677         }
13678
13679         if (cfg->init_ref_vars && cfg->method == method) {
13680                 /* Emit initialization for ref vars */
13681                 // FIXME: Avoid duplication initialization for IL locals.
13682                 for (i = 0; i < cfg->num_varinfo; ++i) {
13683                         MonoInst *ins = cfg->varinfo [i];
13684
13685                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13686                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13687                 }
13688         }
13689
13690         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13691                 cfg->cbb = init_localsbb;
13692                 emit_push_lmf (cfg);
13693         }
13694
13695         cfg->cbb = init_localsbb;
13696         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13697
13698         if (seq_points) {
13699                 MonoBasicBlock *bb;
13700
13701                 /*
13702                  * Make seq points at backward branch targets interruptable.
13703                  */
13704                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13705                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13706                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13707         }
13708
13709         /* Add a sequence point for method entry/exit events */
13710         if (seq_points && cfg->gen_sdb_seq_points) {
13711                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13712                 MONO_ADD_INS (init_localsbb, ins);
13713                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13714                 MONO_ADD_INS (cfg->bb_exit, ins);
13715         }
13716
13717         /*
13718          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13719          * the code they refer to was dead (#11880).
13720          */
13721         if (sym_seq_points) {
13722                 for (i = 0; i < header->code_size; ++i) {
13723                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13724                                 MonoInst *ins;
13725
13726                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13727                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13728                         }
13729                 }
13730         }
13731
13732         cfg->ip = NULL;
13733
13734         if (cfg->method == method) {
13735                 MonoBasicBlock *bb;
13736                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13737                         if (bb == cfg->bb_init)
13738                                 bb->region = -1;
13739                         else
13740                                 bb->region = mono_find_block_region (cfg, bb->real_offset);
13741                         if (cfg->spvars)
13742                                 mono_create_spvar_for_region (cfg, bb->region);
13743                         if (cfg->verbose_level > 2)
13744                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13745                 }
13746         } else {
13747                 MonoBasicBlock *bb;
13748                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
13749                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
13750                         bb->real_offset = inline_offset;
13751                 }
13752         }
13753
13754         if (inline_costs < 0) {
13755                 char *mname;
13756
13757                 /* Method is too large */
13758                 mname = mono_method_full_name (method, TRUE);
13759                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13760                 g_free (mname);
13761         }
13762
13763         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13764                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13765
13766         goto cleanup;
13767
13768 mono_error_exit:
13769         g_assert (!mono_error_ok (&cfg->error));
13770         goto cleanup;
13771  
13772  exception_exit:
13773         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13774         goto cleanup;
13775
13776  unverified:
13777         set_exception_type_from_invalid_il (cfg, method, ip);
13778         goto cleanup;
13779
13780  cleanup:
13781         g_slist_free (class_inits);
13782         mono_basic_block_free (original_bb);
13783         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13784         if (cfg->exception_type)
13785                 return -1;
13786         else
13787                 return inline_costs;
13788 }
13789
13790 static int
13791 store_membase_reg_to_store_membase_imm (int opcode)
13792 {
13793         switch (opcode) {
13794         case OP_STORE_MEMBASE_REG:
13795                 return OP_STORE_MEMBASE_IMM;
13796         case OP_STOREI1_MEMBASE_REG:
13797                 return OP_STOREI1_MEMBASE_IMM;
13798         case OP_STOREI2_MEMBASE_REG:
13799                 return OP_STOREI2_MEMBASE_IMM;
13800         case OP_STOREI4_MEMBASE_REG:
13801                 return OP_STOREI4_MEMBASE_IMM;
13802         case OP_STOREI8_MEMBASE_REG:
13803                 return OP_STOREI8_MEMBASE_IMM;
13804         default:
13805                 g_assert_not_reached ();
13806         }
13807
13808         return -1;
13809 }               
13810
13811 int
13812 mono_op_to_op_imm (int opcode)
13813 {
13814         switch (opcode) {
13815         case OP_IADD:
13816                 return OP_IADD_IMM;
13817         case OP_ISUB:
13818                 return OP_ISUB_IMM;
13819         case OP_IDIV:
13820                 return OP_IDIV_IMM;
13821         case OP_IDIV_UN:
13822                 return OP_IDIV_UN_IMM;
13823         case OP_IREM:
13824                 return OP_IREM_IMM;
13825         case OP_IREM_UN:
13826                 return OP_IREM_UN_IMM;
13827         case OP_IMUL:
13828                 return OP_IMUL_IMM;
13829         case OP_IAND:
13830                 return OP_IAND_IMM;
13831         case OP_IOR:
13832                 return OP_IOR_IMM;
13833         case OP_IXOR:
13834                 return OP_IXOR_IMM;
13835         case OP_ISHL:
13836                 return OP_ISHL_IMM;
13837         case OP_ISHR:
13838                 return OP_ISHR_IMM;
13839         case OP_ISHR_UN:
13840                 return OP_ISHR_UN_IMM;
13841
13842         case OP_LADD:
13843                 return OP_LADD_IMM;
13844         case OP_LSUB:
13845                 return OP_LSUB_IMM;
13846         case OP_LAND:
13847                 return OP_LAND_IMM;
13848         case OP_LOR:
13849                 return OP_LOR_IMM;
13850         case OP_LXOR:
13851                 return OP_LXOR_IMM;
13852         case OP_LSHL:
13853                 return OP_LSHL_IMM;
13854         case OP_LSHR:
13855                 return OP_LSHR_IMM;
13856         case OP_LSHR_UN:
13857                 return OP_LSHR_UN_IMM;
13858 #if SIZEOF_REGISTER == 8
13859         case OP_LREM:
13860                 return OP_LREM_IMM;
13861 #endif
13862
13863         case OP_COMPARE:
13864                 return OP_COMPARE_IMM;
13865         case OP_ICOMPARE:
13866                 return OP_ICOMPARE_IMM;
13867         case OP_LCOMPARE:
13868                 return OP_LCOMPARE_IMM;
13869
13870         case OP_STORE_MEMBASE_REG:
13871                 return OP_STORE_MEMBASE_IMM;
13872         case OP_STOREI1_MEMBASE_REG:
13873                 return OP_STOREI1_MEMBASE_IMM;
13874         case OP_STOREI2_MEMBASE_REG:
13875                 return OP_STOREI2_MEMBASE_IMM;
13876         case OP_STOREI4_MEMBASE_REG:
13877                 return OP_STOREI4_MEMBASE_IMM;
13878
13879 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13880         case OP_X86_PUSH:
13881                 return OP_X86_PUSH_IMM;
13882         case OP_X86_COMPARE_MEMBASE_REG:
13883                 return OP_X86_COMPARE_MEMBASE_IMM;
13884 #endif
13885 #if defined(TARGET_AMD64)
13886         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13887                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13888 #endif
13889         case OP_VOIDCALL_REG:
13890                 return OP_VOIDCALL;
13891         case OP_CALL_REG:
13892                 return OP_CALL;
13893         case OP_LCALL_REG:
13894                 return OP_LCALL;
13895         case OP_FCALL_REG:
13896                 return OP_FCALL;
13897         case OP_LOCALLOC:
13898                 return OP_LOCALLOC_IMM;
13899         }
13900
13901         return -1;
13902 }
13903
13904 static int
13905 ldind_to_load_membase (int opcode)
13906 {
13907         switch (opcode) {
13908         case CEE_LDIND_I1:
13909                 return OP_LOADI1_MEMBASE;
13910         case CEE_LDIND_U1:
13911                 return OP_LOADU1_MEMBASE;
13912         case CEE_LDIND_I2:
13913                 return OP_LOADI2_MEMBASE;
13914         case CEE_LDIND_U2:
13915                 return OP_LOADU2_MEMBASE;
13916         case CEE_LDIND_I4:
13917                 return OP_LOADI4_MEMBASE;
13918         case CEE_LDIND_U4:
13919                 return OP_LOADU4_MEMBASE;
13920         case CEE_LDIND_I:
13921                 return OP_LOAD_MEMBASE;
13922         case CEE_LDIND_REF:
13923                 return OP_LOAD_MEMBASE;
13924         case CEE_LDIND_I8:
13925                 return OP_LOADI8_MEMBASE;
13926         case CEE_LDIND_R4:
13927                 return OP_LOADR4_MEMBASE;
13928         case CEE_LDIND_R8:
13929                 return OP_LOADR8_MEMBASE;
13930         default:
13931                 g_assert_not_reached ();
13932         }
13933
13934         return -1;
13935 }
13936
13937 static int
13938 stind_to_store_membase (int opcode)
13939 {
13940         switch (opcode) {
13941         case CEE_STIND_I1:
13942                 return OP_STOREI1_MEMBASE_REG;
13943         case CEE_STIND_I2:
13944                 return OP_STOREI2_MEMBASE_REG;
13945         case CEE_STIND_I4:
13946                 return OP_STOREI4_MEMBASE_REG;
13947         case CEE_STIND_I:
13948         case CEE_STIND_REF:
13949                 return OP_STORE_MEMBASE_REG;
13950         case CEE_STIND_I8:
13951                 return OP_STOREI8_MEMBASE_REG;
13952         case CEE_STIND_R4:
13953                 return OP_STORER4_MEMBASE_REG;
13954         case CEE_STIND_R8:
13955                 return OP_STORER8_MEMBASE_REG;
13956         default:
13957                 g_assert_not_reached ();
13958         }
13959
13960         return -1;
13961 }
13962
13963 int
13964 mono_load_membase_to_load_mem (int opcode)
13965 {
13966         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13967 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13968         switch (opcode) {
13969         case OP_LOAD_MEMBASE:
13970                 return OP_LOAD_MEM;
13971         case OP_LOADU1_MEMBASE:
13972                 return OP_LOADU1_MEM;
13973         case OP_LOADU2_MEMBASE:
13974                 return OP_LOADU2_MEM;
13975         case OP_LOADI4_MEMBASE:
13976                 return OP_LOADI4_MEM;
13977         case OP_LOADU4_MEMBASE:
13978                 return OP_LOADU4_MEM;
13979 #if SIZEOF_REGISTER == 8
13980         case OP_LOADI8_MEMBASE:
13981                 return OP_LOADI8_MEM;
13982 #endif
13983         }
13984 #endif
13985
13986         return -1;
13987 }
13988
13989 static inline int
13990 op_to_op_dest_membase (int store_opcode, int opcode)
13991 {
13992 #if defined(TARGET_X86)
13993         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13994                 return -1;
13995
13996         switch (opcode) {
13997         case OP_IADD:
13998                 return OP_X86_ADD_MEMBASE_REG;
13999         case OP_ISUB:
14000                 return OP_X86_SUB_MEMBASE_REG;
14001         case OP_IAND:
14002                 return OP_X86_AND_MEMBASE_REG;
14003         case OP_IOR:
14004                 return OP_X86_OR_MEMBASE_REG;
14005         case OP_IXOR:
14006                 return OP_X86_XOR_MEMBASE_REG;
14007         case OP_ADD_IMM:
14008         case OP_IADD_IMM:
14009                 return OP_X86_ADD_MEMBASE_IMM;
14010         case OP_SUB_IMM:
14011         case OP_ISUB_IMM:
14012                 return OP_X86_SUB_MEMBASE_IMM;
14013         case OP_AND_IMM:
14014         case OP_IAND_IMM:
14015                 return OP_X86_AND_MEMBASE_IMM;
14016         case OP_OR_IMM:
14017         case OP_IOR_IMM:
14018                 return OP_X86_OR_MEMBASE_IMM;
14019         case OP_XOR_IMM:
14020         case OP_IXOR_IMM:
14021                 return OP_X86_XOR_MEMBASE_IMM;
14022         case OP_MOVE:
14023                 return OP_NOP;
14024         }
14025 #endif
14026
14027 #if defined(TARGET_AMD64)
14028         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
14029                 return -1;
14030
14031         switch (opcode) {
14032         case OP_IADD:
14033                 return OP_X86_ADD_MEMBASE_REG;
14034         case OP_ISUB:
14035                 return OP_X86_SUB_MEMBASE_REG;
14036         case OP_IAND:
14037                 return OP_X86_AND_MEMBASE_REG;
14038         case OP_IOR:
14039                 return OP_X86_OR_MEMBASE_REG;
14040         case OP_IXOR:
14041                 return OP_X86_XOR_MEMBASE_REG;
14042         case OP_IADD_IMM:
14043                 return OP_X86_ADD_MEMBASE_IMM;
14044         case OP_ISUB_IMM:
14045                 return OP_X86_SUB_MEMBASE_IMM;
14046         case OP_IAND_IMM:
14047                 return OP_X86_AND_MEMBASE_IMM;
14048         case OP_IOR_IMM:
14049                 return OP_X86_OR_MEMBASE_IMM;
14050         case OP_IXOR_IMM:
14051                 return OP_X86_XOR_MEMBASE_IMM;
14052         case OP_LADD:
14053                 return OP_AMD64_ADD_MEMBASE_REG;
14054         case OP_LSUB:
14055                 return OP_AMD64_SUB_MEMBASE_REG;
14056         case OP_LAND:
14057                 return OP_AMD64_AND_MEMBASE_REG;
14058         case OP_LOR:
14059                 return OP_AMD64_OR_MEMBASE_REG;
14060         case OP_LXOR:
14061                 return OP_AMD64_XOR_MEMBASE_REG;
14062         case OP_ADD_IMM:
14063         case OP_LADD_IMM:
14064                 return OP_AMD64_ADD_MEMBASE_IMM;
14065         case OP_SUB_IMM:
14066         case OP_LSUB_IMM:
14067                 return OP_AMD64_SUB_MEMBASE_IMM;
14068         case OP_AND_IMM:
14069         case OP_LAND_IMM:
14070                 return OP_AMD64_AND_MEMBASE_IMM;
14071         case OP_OR_IMM:
14072         case OP_LOR_IMM:
14073                 return OP_AMD64_OR_MEMBASE_IMM;
14074         case OP_XOR_IMM:
14075         case OP_LXOR_IMM:
14076                 return OP_AMD64_XOR_MEMBASE_IMM;
14077         case OP_MOVE:
14078                 return OP_NOP;
14079         }
14080 #endif
14081
14082         return -1;
14083 }
14084
14085 static inline int
14086 op_to_op_store_membase (int store_opcode, int opcode)
14087 {
14088 #if defined(TARGET_X86) || defined(TARGET_AMD64)
14089         switch (opcode) {
14090         case OP_ICEQ:
14091                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
14092                         return OP_X86_SETEQ_MEMBASE;
14093         case OP_CNE:
14094                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
14095                         return OP_X86_SETNE_MEMBASE;
14096         }
14097 #endif
14098
14099         return -1;
14100 }
14101
14102 static inline int
14103 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
14104 {
14105 #ifdef TARGET_X86
14106         /* FIXME: This has sign extension issues */
14107         /*
14108         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14109                 return OP_X86_COMPARE_MEMBASE8_IMM;
14110         */
14111
14112         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14113                 return -1;
14114
14115         switch (opcode) {
14116         case OP_X86_PUSH:
14117                 return OP_X86_PUSH_MEMBASE;
14118         case OP_COMPARE_IMM:
14119         case OP_ICOMPARE_IMM:
14120                 return OP_X86_COMPARE_MEMBASE_IMM;
14121         case OP_COMPARE:
14122         case OP_ICOMPARE:
14123                 return OP_X86_COMPARE_MEMBASE_REG;
14124         }
14125 #endif
14126
14127 #ifdef TARGET_AMD64
14128         /* FIXME: This has sign extension issues */
14129         /*
14130         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14131                 return OP_X86_COMPARE_MEMBASE8_IMM;
14132         */
14133
14134         switch (opcode) {
14135         case OP_X86_PUSH:
14136                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14137                         return OP_X86_PUSH_MEMBASE;
14138                 break;
14139                 /* FIXME: This only works for 32 bit immediates
14140         case OP_COMPARE_IMM:
14141         case OP_LCOMPARE_IMM:
14142                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14143                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14144                 */
14145         case OP_ICOMPARE_IMM:
14146                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14147                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14148                 break;
14149         case OP_COMPARE:
14150         case OP_LCOMPARE:
14151                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14152                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14153                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14154                         return OP_AMD64_COMPARE_MEMBASE_REG;
14155                 break;
14156         case OP_ICOMPARE:
14157                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14158                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14159                 break;
14160         }
14161 #endif
14162
14163         return -1;
14164 }
14165
14166 static inline int
14167 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14168 {
14169 #ifdef TARGET_X86
14170         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14171                 return -1;
14172         
14173         switch (opcode) {
14174         case OP_COMPARE:
14175         case OP_ICOMPARE:
14176                 return OP_X86_COMPARE_REG_MEMBASE;
14177         case OP_IADD:
14178                 return OP_X86_ADD_REG_MEMBASE;
14179         case OP_ISUB:
14180                 return OP_X86_SUB_REG_MEMBASE;
14181         case OP_IAND:
14182                 return OP_X86_AND_REG_MEMBASE;
14183         case OP_IOR:
14184                 return OP_X86_OR_REG_MEMBASE;
14185         case OP_IXOR:
14186                 return OP_X86_XOR_REG_MEMBASE;
14187         }
14188 #endif
14189
14190 #ifdef TARGET_AMD64
14191         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14192                 switch (opcode) {
14193                 case OP_ICOMPARE:
14194                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14195                 case OP_IADD:
14196                         return OP_X86_ADD_REG_MEMBASE;
14197                 case OP_ISUB:
14198                         return OP_X86_SUB_REG_MEMBASE;
14199                 case OP_IAND:
14200                         return OP_X86_AND_REG_MEMBASE;
14201                 case OP_IOR:
14202                         return OP_X86_OR_REG_MEMBASE;
14203                 case OP_IXOR:
14204                         return OP_X86_XOR_REG_MEMBASE;
14205                 }
14206         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14207                 switch (opcode) {
14208                 case OP_COMPARE:
14209                 case OP_LCOMPARE:
14210                         return OP_AMD64_COMPARE_REG_MEMBASE;
14211                 case OP_LADD:
14212                         return OP_AMD64_ADD_REG_MEMBASE;
14213                 case OP_LSUB:
14214                         return OP_AMD64_SUB_REG_MEMBASE;
14215                 case OP_LAND:
14216                         return OP_AMD64_AND_REG_MEMBASE;
14217                 case OP_LOR:
14218                         return OP_AMD64_OR_REG_MEMBASE;
14219                 case OP_LXOR:
14220                         return OP_AMD64_XOR_REG_MEMBASE;
14221                 }
14222         }
14223 #endif
14224
14225         return -1;
14226 }
14227
14228 int
14229 mono_op_to_op_imm_noemul (int opcode)
14230 {
14231         switch (opcode) {
14232 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14233         case OP_LSHR:
14234         case OP_LSHL:
14235         case OP_LSHR_UN:
14236                 return -1;
14237 #endif
14238 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14239         case OP_IDIV:
14240         case OP_IDIV_UN:
14241         case OP_IREM:
14242         case OP_IREM_UN:
14243                 return -1;
14244 #endif
14245 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14246         case OP_IMUL:
14247                 return -1;
14248 #endif
14249         default:
14250                 return mono_op_to_op_imm (opcode);
14251         }
14252 }
14253
14254 /**
14255  * mono_handle_global_vregs:
14256  *
14257  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14258  * for them.
14259  */
14260 void
14261 mono_handle_global_vregs (MonoCompile *cfg)
14262 {
14263         gint32 *vreg_to_bb;
14264         MonoBasicBlock *bb;
14265         int i, pos;
14266
14267         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14268
14269 #ifdef MONO_ARCH_SIMD_INTRINSICS
14270         if (cfg->uses_simd_intrinsics)
14271                 mono_simd_simplify_indirection (cfg);
14272 #endif
14273
14274         /* Find local vregs used in more than one bb */
14275         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14276                 MonoInst *ins = bb->code;       
14277                 int block_num = bb->block_num;
14278
14279                 if (cfg->verbose_level > 2)
14280                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14281
14282                 cfg->cbb = bb;
14283                 for (; ins; ins = ins->next) {
14284                         const char *spec = INS_INFO (ins->opcode);
14285                         int regtype = 0, regindex;
14286                         gint32 prev_bb;
14287
14288                         if (G_UNLIKELY (cfg->verbose_level > 2))
14289                                 mono_print_ins (ins);
14290
14291                         g_assert (ins->opcode >= MONO_CEE_LAST);
14292
14293                         for (regindex = 0; regindex < 4; regindex ++) {
14294                                 int vreg = 0;
14295
14296                                 if (regindex == 0) {
14297                                         regtype = spec [MONO_INST_DEST];
14298                                         if (regtype == ' ')
14299                                                 continue;
14300                                         vreg = ins->dreg;
14301                                 } else if (regindex == 1) {
14302                                         regtype = spec [MONO_INST_SRC1];
14303                                         if (regtype == ' ')
14304                                                 continue;
14305                                         vreg = ins->sreg1;
14306                                 } else if (regindex == 2) {
14307                                         regtype = spec [MONO_INST_SRC2];
14308                                         if (regtype == ' ')
14309                                                 continue;
14310                                         vreg = ins->sreg2;
14311                                 } else if (regindex == 3) {
14312                                         regtype = spec [MONO_INST_SRC3];
14313                                         if (regtype == ' ')
14314                                                 continue;
14315                                         vreg = ins->sreg3;
14316                                 }
14317
14318 #if SIZEOF_REGISTER == 4
14319                                 /* In the LLVM case, the long opcodes are not decomposed */
14320                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14321                                         /*
14322                                          * Since some instructions reference the original long vreg,
14323                                          * and some reference the two component vregs, it is quite hard
14324                                          * to determine when it needs to be global. So be conservative.
14325                                          */
14326                                         if (!get_vreg_to_inst (cfg, vreg)) {
14327                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14328
14329                                                 if (cfg->verbose_level > 2)
14330                                                         printf ("LONG VREG R%d made global.\n", vreg);
14331                                         }
14332
14333                                         /*
14334                                          * Make the component vregs volatile since the optimizations can
14335                                          * get confused otherwise.
14336                                          */
14337                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14338                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14339                                 }
14340 #endif
14341
14342                                 g_assert (vreg != -1);
14343
14344                                 prev_bb = vreg_to_bb [vreg];
14345                                 if (prev_bb == 0) {
14346                                         /* 0 is a valid block num */
14347                                         vreg_to_bb [vreg] = block_num + 1;
14348                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14349                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14350                                                 continue;
14351
14352                                         if (!get_vreg_to_inst (cfg, vreg)) {
14353                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14354                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14355
14356                                                 switch (regtype) {
14357                                                 case 'i':
14358                                                         if (vreg_is_ref (cfg, vreg))
14359                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14360                                                         else
14361                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14362                                                         break;
14363                                                 case 'l':
14364                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14365                                                         break;
14366                                                 case 'f':
14367                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14368                                                         break;
14369                                                 case 'v':
14370                                                 case 'x':
14371                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14372                                                         break;
14373                                                 default:
14374                                                         g_assert_not_reached ();
14375                                                 }
14376                                         }
14377
14378                                         /* Flag as having been used in more than one bb */
14379                                         vreg_to_bb [vreg] = -1;
14380                                 }
14381                         }
14382                 }
14383         }
14384
14385         /* If a variable is used in only one bblock, convert it into a local vreg */
14386         for (i = 0; i < cfg->num_varinfo; i++) {
14387                 MonoInst *var = cfg->varinfo [i];
14388                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14389
14390                 switch (var->type) {
14391                 case STACK_I4:
14392                 case STACK_OBJ:
14393                 case STACK_PTR:
14394                 case STACK_MP:
14395                 case STACK_VTYPE:
14396 #if SIZEOF_REGISTER == 8
14397                 case STACK_I8:
14398 #endif
14399 #if !defined(TARGET_X86)
14400                 /* Enabling this screws up the fp stack on x86 */
14401                 case STACK_R8:
14402 #endif
14403                         if (mono_arch_is_soft_float ())
14404                                 break;
14405
14406                         /*
14407                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14408                                 break;
14409                         */
14410
14411                         /* Arguments are implicitly global */
14412                         /* Putting R4 vars into registers doesn't work currently */
14413                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14414                         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) {
14415                                 /* 
14416                                  * Make that the variable's liveness interval doesn't contain a call, since
14417                                  * that would cause the lvreg to be spilled, making the whole optimization
14418                                  * useless.
14419                                  */
14420                                 /* This is too slow for JIT compilation */
14421 #if 0
14422                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14423                                         MonoInst *ins;
14424                                         int def_index, call_index, ins_index;
14425                                         gboolean spilled = FALSE;
14426
14427                                         def_index = -1;
14428                                         call_index = -1;
14429                                         ins_index = 0;
14430                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14431                                                 const char *spec = INS_INFO (ins->opcode);
14432
14433                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14434                                                         def_index = ins_index;
14435
14436                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14437                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14438                                                         if (call_index > def_index) {
14439                                                                 spilled = TRUE;
14440                                                                 break;
14441                                                         }
14442                                                 }
14443
14444                                                 if (MONO_IS_CALL (ins))
14445                                                         call_index = ins_index;
14446
14447                                                 ins_index ++;
14448                                         }
14449
14450                                         if (spilled)
14451                                                 break;
14452                                 }
14453 #endif
14454
14455                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14456                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14457                                 var->flags |= MONO_INST_IS_DEAD;
14458                                 cfg->vreg_to_inst [var->dreg] = NULL;
14459                         }
14460                         break;
14461                 }
14462         }
14463
14464         /* 
14465          * Compress the varinfo and vars tables so the liveness computation is faster and
14466          * takes up less space.
14467          */
14468         pos = 0;
14469         for (i = 0; i < cfg->num_varinfo; ++i) {
14470                 MonoInst *var = cfg->varinfo [i];
14471                 if (pos < i && cfg->locals_start == i)
14472                         cfg->locals_start = pos;
14473                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14474                         if (pos < i) {
14475                                 cfg->varinfo [pos] = cfg->varinfo [i];
14476                                 cfg->varinfo [pos]->inst_c0 = pos;
14477                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14478                                 cfg->vars [pos].idx = pos;
14479 #if SIZEOF_REGISTER == 4
14480                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14481                                         /* Modify the two component vars too */
14482                                         MonoInst *var1;
14483
14484                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14485                                         var1->inst_c0 = pos;
14486                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14487                                         var1->inst_c0 = pos;
14488                                 }
14489 #endif
14490                         }
14491                         pos ++;
14492                 }
14493         }
14494         cfg->num_varinfo = pos;
14495         if (cfg->locals_start > cfg->num_varinfo)
14496                 cfg->locals_start = cfg->num_varinfo;
14497 }
14498
14499 /*
14500  * mono_allocate_gsharedvt_vars:
14501  *
14502  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14503  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14504  */
14505 void
14506 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14507 {
14508         int i;
14509
14510         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14511
14512         for (i = 0; i < cfg->num_varinfo; ++i) {
14513                 MonoInst *ins = cfg->varinfo [i];
14514                 int idx;
14515
14516                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14517                         if (i >= cfg->locals_start) {
14518                                 /* Local */
14519                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14520                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14521                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14522                                 ins->inst_imm = idx;
14523                         } else {
14524                                 /* Arg */
14525                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14526                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14527                         }
14528                 }
14529         }
14530 }
14531
14532 /**
14533  * mono_spill_global_vars:
14534  *
14535  *   Generate spill code for variables which are not allocated to registers, 
14536  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14537  * code is generated which could be optimized by the local optimization passes.
14538  */
14539 void
14540 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14541 {
14542         MonoBasicBlock *bb;
14543         char spec2 [16];
14544         int orig_next_vreg;
14545         guint32 *vreg_to_lvreg;
14546         guint32 *lvregs;
14547         guint32 i, lvregs_len;
14548         gboolean dest_has_lvreg = FALSE;
14549         MonoStackType stacktypes [128];
14550         MonoInst **live_range_start, **live_range_end;
14551         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14552
14553         *need_local_opts = FALSE;
14554
14555         memset (spec2, 0, sizeof (spec2));
14556
14557         /* FIXME: Move this function to mini.c */
14558         stacktypes ['i'] = STACK_PTR;
14559         stacktypes ['l'] = STACK_I8;
14560         stacktypes ['f'] = STACK_R8;
14561 #ifdef MONO_ARCH_SIMD_INTRINSICS
14562         stacktypes ['x'] = STACK_VTYPE;
14563 #endif
14564
14565 #if SIZEOF_REGISTER == 4
14566         /* Create MonoInsts for longs */
14567         for (i = 0; i < cfg->num_varinfo; i++) {
14568                 MonoInst *ins = cfg->varinfo [i];
14569
14570                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14571                         switch (ins->type) {
14572                         case STACK_R8:
14573                         case STACK_I8: {
14574                                 MonoInst *tree;
14575
14576                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14577                                         break;
14578
14579                                 g_assert (ins->opcode == OP_REGOFFSET);
14580
14581                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
14582                                 g_assert (tree);
14583                                 tree->opcode = OP_REGOFFSET;
14584                                 tree->inst_basereg = ins->inst_basereg;
14585                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14586
14587                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
14588                                 g_assert (tree);
14589                                 tree->opcode = OP_REGOFFSET;
14590                                 tree->inst_basereg = ins->inst_basereg;
14591                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14592                                 break;
14593                         }
14594                         default:
14595                                 break;
14596                         }
14597                 }
14598         }
14599 #endif
14600
14601         if (cfg->compute_gc_maps) {
14602                 /* registers need liveness info even for !non refs */
14603                 for (i = 0; i < cfg->num_varinfo; i++) {
14604                         MonoInst *ins = cfg->varinfo [i];
14605
14606                         if (ins->opcode == OP_REGVAR)
14607                                 ins->flags |= MONO_INST_GC_TRACK;
14608                 }
14609         }
14610                 
14611         /* FIXME: widening and truncation */
14612
14613         /*
14614          * As an optimization, when a variable allocated to the stack is first loaded into 
14615          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14616          * the variable again.
14617          */
14618         orig_next_vreg = cfg->next_vreg;
14619         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14620         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14621         lvregs_len = 0;
14622
14623         /* 
14624          * These arrays contain the first and last instructions accessing a given
14625          * variable.
14626          * Since we emit bblocks in the same order we process them here, and we
14627          * don't split live ranges, these will precisely describe the live range of
14628          * the variable, i.e. the instruction range where a valid value can be found
14629          * in the variables location.
14630          * The live range is computed using the liveness info computed by the liveness pass.
14631          * We can't use vmv->range, since that is an abstract live range, and we need
14632          * one which is instruction precise.
14633          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14634          */
14635         /* FIXME: Only do this if debugging info is requested */
14636         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14637         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14638         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14639         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14640         
14641         /* Add spill loads/stores */
14642         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14643                 MonoInst *ins;
14644
14645                 if (cfg->verbose_level > 2)
14646                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14647
14648                 /* Clear vreg_to_lvreg array */
14649                 for (i = 0; i < lvregs_len; i++)
14650                         vreg_to_lvreg [lvregs [i]] = 0;
14651                 lvregs_len = 0;
14652
14653                 cfg->cbb = bb;
14654                 MONO_BB_FOR_EACH_INS (bb, ins) {
14655                         const char *spec = INS_INFO (ins->opcode);
14656                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14657                         gboolean store, no_lvreg;
14658                         int sregs [MONO_MAX_SRC_REGS];
14659
14660                         if (G_UNLIKELY (cfg->verbose_level > 2))
14661                                 mono_print_ins (ins);
14662
14663                         if (ins->opcode == OP_NOP)
14664                                 continue;
14665
14666                         /* 
14667                          * We handle LDADDR here as well, since it can only be decomposed
14668                          * when variable addresses are known.
14669                          */
14670                         if (ins->opcode == OP_LDADDR) {
14671                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14672
14673                                 if (var->opcode == OP_VTARG_ADDR) {
14674                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14675                                         MonoInst *vtaddr = var->inst_left;
14676                                         if (vtaddr->opcode == OP_REGVAR) {
14677                                                 ins->opcode = OP_MOVE;
14678                                                 ins->sreg1 = vtaddr->dreg;
14679                                         }
14680                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14681                                                 ins->opcode = OP_LOAD_MEMBASE;
14682                                                 ins->inst_basereg = vtaddr->inst_basereg;
14683                                                 ins->inst_offset = vtaddr->inst_offset;
14684                                         } else
14685                                                 NOT_IMPLEMENTED;
14686                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14687                                         /* gsharedvt arg passed by ref */
14688                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14689
14690                                         ins->opcode = OP_LOAD_MEMBASE;
14691                                         ins->inst_basereg = var->inst_basereg;
14692                                         ins->inst_offset = var->inst_offset;
14693                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14694                                         MonoInst *load, *load2, *load3;
14695                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14696                                         int reg1, reg2, reg3;
14697                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14698                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14699
14700                                         /*
14701                                          * gsharedvt local.
14702                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14703                                          */
14704
14705                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14706
14707                                         g_assert (info_var);
14708                                         g_assert (locals_var);
14709
14710                                         /* Mark the instruction used to compute the locals var as used */
14711                                         cfg->gsharedvt_locals_var_ins = NULL;
14712
14713                                         /* Load the offset */
14714                                         if (info_var->opcode == OP_REGOFFSET) {
14715                                                 reg1 = alloc_ireg (cfg);
14716                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14717                                         } else if (info_var->opcode == OP_REGVAR) {
14718                                                 load = NULL;
14719                                                 reg1 = info_var->dreg;
14720                                         } else {
14721                                                 g_assert_not_reached ();
14722                                         }
14723                                         reg2 = alloc_ireg (cfg);
14724                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14725                                         /* Load the locals area address */
14726                                         reg3 = alloc_ireg (cfg);
14727                                         if (locals_var->opcode == OP_REGOFFSET) {
14728                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14729                                         } else if (locals_var->opcode == OP_REGVAR) {
14730                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14731                                         } else {
14732                                                 g_assert_not_reached ();
14733                                         }
14734                                         /* Compute the address */
14735                                         ins->opcode = OP_PADD;
14736                                         ins->sreg1 = reg3;
14737                                         ins->sreg2 = reg2;
14738
14739                                         mono_bblock_insert_before_ins (bb, ins, load3);
14740                                         mono_bblock_insert_before_ins (bb, load3, load2);
14741                                         if (load)
14742                                                 mono_bblock_insert_before_ins (bb, load2, load);
14743                                 } else {
14744                                         g_assert (var->opcode == OP_REGOFFSET);
14745
14746                                         ins->opcode = OP_ADD_IMM;
14747                                         ins->sreg1 = var->inst_basereg;
14748                                         ins->inst_imm = var->inst_offset;
14749                                 }
14750
14751                                 *need_local_opts = TRUE;
14752                                 spec = INS_INFO (ins->opcode);
14753                         }
14754
14755                         if (ins->opcode < MONO_CEE_LAST) {
14756                                 mono_print_ins (ins);
14757                                 g_assert_not_reached ();
14758                         }
14759
14760                         /*
14761                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14762                          * src register.
14763                          * FIXME:
14764                          */
14765                         if (MONO_IS_STORE_MEMBASE (ins)) {
14766                                 tmp_reg = ins->dreg;
14767                                 ins->dreg = ins->sreg2;
14768                                 ins->sreg2 = tmp_reg;
14769                                 store = TRUE;
14770
14771                                 spec2 [MONO_INST_DEST] = ' ';
14772                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14773                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14774                                 spec2 [MONO_INST_SRC3] = ' ';
14775                                 spec = spec2;
14776                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14777                                 g_assert_not_reached ();
14778                         else
14779                                 store = FALSE;
14780                         no_lvreg = FALSE;
14781
14782                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14783                                 printf ("\t %.3s %d", spec, ins->dreg);
14784                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14785                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14786                                         printf (" %d", sregs [srcindex]);
14787                                 printf ("\n");
14788                         }
14789
14790                         /***************/
14791                         /*    DREG     */
14792                         /***************/
14793                         regtype = spec [MONO_INST_DEST];
14794                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14795                         prev_dreg = -1;
14796
14797                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14798                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14799                                 MonoInst *store_ins;
14800                                 int store_opcode;
14801                                 MonoInst *def_ins = ins;
14802                                 int dreg = ins->dreg; /* The original vreg */
14803
14804                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14805
14806                                 if (var->opcode == OP_REGVAR) {
14807                                         ins->dreg = var->dreg;
14808                                 } 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)) {
14809                                         /* 
14810                                          * Instead of emitting a load+store, use a _membase opcode.
14811                                          */
14812                                         g_assert (var->opcode == OP_REGOFFSET);
14813                                         if (ins->opcode == OP_MOVE) {
14814                                                 NULLIFY_INS (ins);
14815                                                 def_ins = NULL;
14816                                         } else {
14817                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14818                                                 ins->inst_basereg = var->inst_basereg;
14819                                                 ins->inst_offset = var->inst_offset;
14820                                                 ins->dreg = -1;
14821                                         }
14822                                         spec = INS_INFO (ins->opcode);
14823                                 } else {
14824                                         guint32 lvreg;
14825
14826                                         g_assert (var->opcode == OP_REGOFFSET);
14827
14828                                         prev_dreg = ins->dreg;
14829
14830                                         /* Invalidate any previous lvreg for this vreg */
14831                                         vreg_to_lvreg [ins->dreg] = 0;
14832
14833                                         lvreg = 0;
14834
14835                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14836                                                 regtype = 'l';
14837                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14838                                         }
14839
14840                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14841
14842 #if SIZEOF_REGISTER != 8
14843                                         if (regtype == 'l') {
14844                                                 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));
14845                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14846                                                 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));
14847                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14848                                                 def_ins = store_ins;
14849                                         }
14850                                         else
14851 #endif
14852                                         {
14853                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14854
14855                                                 /* Try to fuse the store into the instruction itself */
14856                                                 /* FIXME: Add more instructions */
14857                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14858                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14859                                                         ins->inst_imm = ins->inst_c0;
14860                                                         ins->inst_destbasereg = var->inst_basereg;
14861                                                         ins->inst_offset = var->inst_offset;
14862                                                         spec = INS_INFO (ins->opcode);
14863                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14864                                                         ins->opcode = store_opcode;
14865                                                         ins->inst_destbasereg = var->inst_basereg;
14866                                                         ins->inst_offset = var->inst_offset;
14867
14868                                                         no_lvreg = TRUE;
14869
14870                                                         tmp_reg = ins->dreg;
14871                                                         ins->dreg = ins->sreg2;
14872                                                         ins->sreg2 = tmp_reg;
14873                                                         store = TRUE;
14874
14875                                                         spec2 [MONO_INST_DEST] = ' ';
14876                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14877                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14878                                                         spec2 [MONO_INST_SRC3] = ' ';
14879                                                         spec = spec2;
14880                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14881                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14882                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14883                                                         ins->dreg = -1;
14884                                                         ins->inst_basereg = var->inst_basereg;
14885                                                         ins->inst_offset = var->inst_offset;
14886                                                         spec = INS_INFO (ins->opcode);
14887                                                 } else {
14888                                                         /* printf ("INS: "); mono_print_ins (ins); */
14889                                                         /* Create a store instruction */
14890                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14891
14892                                                         /* Insert it after the instruction */
14893                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14894
14895                                                         def_ins = store_ins;
14896
14897                                                         /* 
14898                                                          * We can't assign ins->dreg to var->dreg here, since the
14899                                                          * sregs could use it. So set a flag, and do it after
14900                                                          * the sregs.
14901                                                          */
14902                                                         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)))
14903                                                                 dest_has_lvreg = TRUE;
14904                                                 }
14905                                         }
14906                                 }
14907
14908                                 if (def_ins && !live_range_start [dreg]) {
14909                                         live_range_start [dreg] = def_ins;
14910                                         live_range_start_bb [dreg] = bb;
14911                                 }
14912
14913                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14914                                         MonoInst *tmp;
14915
14916                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14917                                         tmp->inst_c1 = dreg;
14918                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14919                                 }
14920                         }
14921
14922                         /************/
14923                         /*  SREGS   */
14924                         /************/
14925                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14926                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14927                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14928                                 sreg = sregs [srcindex];
14929
14930                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14931                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14932                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14933                                         MonoInst *use_ins = ins;
14934                                         MonoInst *load_ins;
14935                                         guint32 load_opcode;
14936
14937                                         if (var->opcode == OP_REGVAR) {
14938                                                 sregs [srcindex] = var->dreg;
14939                                                 //mono_inst_set_src_registers (ins, sregs);
14940                                                 live_range_end [sreg] = use_ins;
14941                                                 live_range_end_bb [sreg] = bb;
14942
14943                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14944                                                         MonoInst *tmp;
14945
14946                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14947                                                         /* var->dreg is a hreg */
14948                                                         tmp->inst_c1 = sreg;
14949                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14950                                                 }
14951
14952                                                 continue;
14953                                         }
14954
14955                                         g_assert (var->opcode == OP_REGOFFSET);
14956                                                 
14957                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14958
14959                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14960
14961                                         if (vreg_to_lvreg [sreg]) {
14962                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14963
14964                                                 /* The variable is already loaded to an lvreg */
14965                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14966                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14967                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14968                                                 //mono_inst_set_src_registers (ins, sregs);
14969                                                 continue;
14970                                         }
14971
14972                                         /* Try to fuse the load into the instruction */
14973                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14974                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14975                                                 sregs [0] = var->inst_basereg;
14976                                                 //mono_inst_set_src_registers (ins, sregs);
14977                                                 ins->inst_offset = var->inst_offset;
14978                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14979                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14980                                                 sregs [1] = var->inst_basereg;
14981                                                 //mono_inst_set_src_registers (ins, sregs);
14982                                                 ins->inst_offset = var->inst_offset;
14983                                         } else {
14984                                                 if (MONO_IS_REAL_MOVE (ins)) {
14985                                                         ins->opcode = OP_NOP;
14986                                                         sreg = ins->dreg;
14987                                                 } else {
14988                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14989
14990                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14991
14992                                                         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) {
14993                                                                 if (var->dreg == prev_dreg) {
14994                                                                         /*
14995                                                                          * sreg refers to the value loaded by the load
14996                                                                          * emitted below, but we need to use ins->dreg
14997                                                                          * since it refers to the store emitted earlier.
14998                                                                          */
14999                                                                         sreg = ins->dreg;
15000                                                                 }
15001                                                                 g_assert (sreg != -1);
15002                                                                 vreg_to_lvreg [var->dreg] = sreg;
15003                                                                 g_assert (lvregs_len < 1024);
15004                                                                 lvregs [lvregs_len ++] = var->dreg;
15005                                                         }
15006                                                 }
15007
15008                                                 sregs [srcindex] = sreg;
15009                                                 //mono_inst_set_src_registers (ins, sregs);
15010
15011 #if SIZEOF_REGISTER != 8
15012                                                 if (regtype == 'l') {
15013                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
15014                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
15015                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
15016                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
15017                                                         use_ins = load_ins;
15018                                                 }
15019                                                 else
15020 #endif
15021                                                 {
15022 #if SIZEOF_REGISTER == 4
15023                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
15024 #endif
15025                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
15026                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
15027                                                         use_ins = load_ins;
15028                                                 }
15029                                         }
15030
15031                                         if (var->dreg < orig_next_vreg) {
15032                                                 live_range_end [var->dreg] = use_ins;
15033                                                 live_range_end_bb [var->dreg] = bb;
15034                                         }
15035
15036                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
15037                                                 MonoInst *tmp;
15038
15039                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
15040                                                 tmp->inst_c1 = var->dreg;
15041                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
15042                                         }
15043                                 }
15044                         }
15045                         mono_inst_set_src_registers (ins, sregs);
15046
15047                         if (dest_has_lvreg) {
15048                                 g_assert (ins->dreg != -1);
15049                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
15050                                 g_assert (lvregs_len < 1024);
15051                                 lvregs [lvregs_len ++] = prev_dreg;
15052                                 dest_has_lvreg = FALSE;
15053                         }
15054
15055                         if (store) {
15056                                 tmp_reg = ins->dreg;
15057                                 ins->dreg = ins->sreg2;
15058                                 ins->sreg2 = tmp_reg;
15059                         }
15060
15061                         if (MONO_IS_CALL (ins)) {
15062                                 /* Clear vreg_to_lvreg array */
15063                                 for (i = 0; i < lvregs_len; i++)
15064                                         vreg_to_lvreg [lvregs [i]] = 0;
15065                                 lvregs_len = 0;
15066                         } else if (ins->opcode == OP_NOP) {
15067                                 ins->dreg = -1;
15068                                 MONO_INST_NULLIFY_SREGS (ins);
15069                         }
15070
15071                         if (cfg->verbose_level > 2)
15072                                 mono_print_ins_index (1, ins);
15073                 }
15074
15075                 /* Extend the live range based on the liveness info */
15076                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
15077                         for (i = 0; i < cfg->num_varinfo; i ++) {
15078                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
15079
15080                                 if (vreg_is_volatile (cfg, vi->vreg))
15081                                         /* The liveness info is incomplete */
15082                                         continue;
15083
15084                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
15085                                         /* Live from at least the first ins of this bb */
15086                                         live_range_start [vi->vreg] = bb->code;
15087                                         live_range_start_bb [vi->vreg] = bb;
15088                                 }
15089
15090                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
15091                                         /* Live at least until the last ins of this bb */
15092                                         live_range_end [vi->vreg] = bb->last_ins;
15093                                         live_range_end_bb [vi->vreg] = bb;
15094                                 }
15095                         }
15096                 }
15097         }
15098         
15099         /*
15100          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
15101          * by storing the current native offset into MonoMethodVar->live_range_start/end.
15102          */
15103         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
15104                 for (i = 0; i < cfg->num_varinfo; ++i) {
15105                         int vreg = MONO_VARINFO (cfg, i)->vreg;
15106                         MonoInst *ins;
15107
15108                         if (live_range_start [vreg]) {
15109                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
15110                                 ins->inst_c0 = i;
15111                                 ins->inst_c1 = vreg;
15112                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
15113                         }
15114                         if (live_range_end [vreg]) {
15115                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
15116                                 ins->inst_c0 = i;
15117                                 ins->inst_c1 = vreg;
15118                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
15119                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
15120                                 else
15121                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
15122                         }
15123                 }
15124         }
15125
15126         if (cfg->gsharedvt_locals_var_ins) {
15127                 /* Nullify if unused */
15128                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
15129                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
15130         }
15131
15132         g_free (live_range_start);
15133         g_free (live_range_end);
15134         g_free (live_range_start_bb);
15135         g_free (live_range_end_bb);
15136 }
15137
15138 static void
15139 mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
15140 {
15141         MonoInst *ret, *move, *source;
15142         MonoClass *klass = ins->klass;
15143         int context_used = mini_class_check_context_used (cfg, klass);
15144         int is_isinst = ins->opcode == OP_ISINST;
15145         g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
15146         source = get_vreg_to_inst (cfg, ins->sreg1);
15147         if (!source || source == (MonoInst *) -1)
15148                 source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
15149         g_assert (source && source != (MonoInst *) -1);
15150
15151         MonoBasicBlock *first_bb;
15152         NEW_BBLOCK (cfg, first_bb);
15153         cfg->cbb = first_bb;
15154
15155         if (!context_used && (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || klass->is_array_special_interface)) {
15156                 if (is_isinst)
15157                         ret = emit_isinst_with_cache_nonshared (cfg, source, klass);
15158                 else
15159                         ret = emit_castclass_with_cache_nonshared (cfg, source, klass);
15160         } else if (!context_used && (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass))) {
15161                 MonoInst *iargs [1];
15162                 int costs;
15163
15164                 iargs [0] = source;
15165                 if (is_isinst) {
15166                         MonoMethod *wrapper = mono_marshal_get_isinst (klass);
15167                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
15168                 } else {
15169                         MonoMethod *wrapper = mono_marshal_get_castclass (klass);
15170                         save_cast_details (cfg, klass, source->dreg, TRUE);
15171                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
15172                         reset_cast_details (cfg);
15173                 }
15174                 g_assert (costs > 0);
15175                 ret = iargs [0];
15176         } else {
15177                 if (is_isinst)
15178                         ret = handle_isinst (cfg, klass, source, context_used);
15179                 else
15180                         ret = handle_castclass (cfg, klass, source, context_used);
15181         }
15182         EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
15183
15184         g_assert (cfg->cbb->code || first_bb->code);
15185         MonoInst *prev = ins->prev;
15186         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
15187 }
15188
15189 void
15190 mono_decompose_typechecks (MonoCompile *cfg)
15191 {
15192         for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
15193                 MonoInst *ins;
15194                 MONO_BB_FOR_EACH_INS (bb, ins) {
15195                         switch (ins->opcode) {
15196                         case OP_ISINST:
15197                         case OP_CASTCLASS:
15198                                 mono_decompose_typecheck (cfg, bb, ins);
15199                                 break;
15200                         }
15201                 }
15202         }
15203 }
15204
15205
15206 /**
15207  * FIXME:
15208  * - use 'iadd' instead of 'int_add'
15209  * - handling ovf opcodes: decompose in method_to_ir.
15210  * - unify iregs/fregs
15211  *   -> partly done, the missing parts are:
15212  *   - a more complete unification would involve unifying the hregs as well, so
15213  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15214  *     would no longer map to the machine hregs, so the code generators would need to
15215  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15216  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15217  *     fp/non-fp branches speeds it up by about 15%.
15218  * - use sext/zext opcodes instead of shifts
15219  * - add OP_ICALL
15220  * - get rid of TEMPLOADs if possible and use vregs instead
15221  * - clean up usage of OP_P/OP_ opcodes
15222  * - cleanup usage of DUMMY_USE
15223  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15224  *   stack
15225  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15226  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15227  * - make sure handle_stack_args () is called before the branch is emitted
15228  * - when the new IR is done, get rid of all unused stuff
15229  * - COMPARE/BEQ as separate instructions or unify them ?
15230  *   - keeping them separate allows specialized compare instructions like
15231  *     compare_imm, compare_membase
15232  *   - most back ends unify fp compare+branch, fp compare+ceq
15233  * - integrate mono_save_args into inline_method
15234  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15235  * - handle long shift opts on 32 bit platforms somehow: they require 
15236  *   3 sregs (2 for arg1 and 1 for arg2)
15237  * - make byref a 'normal' type.
15238  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15239  *   variable if needed.
15240  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15241  *   like inline_method.
15242  * - remove inlining restrictions
15243  * - fix LNEG and enable cfold of INEG
15244  * - generalize x86 optimizations like ldelema as a peephole optimization
15245  * - add store_mem_imm for amd64
15246  * - optimize the loading of the interruption flag in the managed->native wrappers
15247  * - avoid special handling of OP_NOP in passes
15248  * - move code inserting instructions into one function/macro.
15249  * - try a coalescing phase after liveness analysis
15250  * - add float -> vreg conversion + local optimizations on !x86
15251  * - figure out how to handle decomposed branches during optimizations, ie.
15252  *   compare+branch, op_jump_table+op_br etc.
15253  * - promote RuntimeXHandles to vregs
15254  * - vtype cleanups:
15255  *   - add a NEW_VARLOADA_VREG macro
15256  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15257  *   accessing vtype fields.
15258  * - get rid of I8CONST on 64 bit platforms
15259  * - dealing with the increase in code size due to branches created during opcode
15260  *   decomposition:
15261  *   - use extended basic blocks
15262  *     - all parts of the JIT
15263  *     - handle_global_vregs () && local regalloc
15264  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15265  * - sources of increase in code size:
15266  *   - vtypes
15267  *   - long compares
15268  *   - isinst and castclass
15269  *   - lvregs not allocated to global registers even if used multiple times
15270  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15271  *   meaningful.
15272  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15273  * - add all micro optimizations from the old JIT
15274  * - put tree optimizations into the deadce pass
15275  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15276  *   specific function.
15277  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15278  *   fcompare + branchCC.
15279  * - create a helper function for allocating a stack slot, taking into account 
15280  *   MONO_CFG_HAS_SPILLUP.
15281  * - merge r68207.
15282  * - merge the ia64 switch changes.
15283  * - optimize mono_regstate2_alloc_int/float.
15284  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15285  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15286  *   parts of the tree could be separated by other instructions, killing the tree
15287  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15288  *   instructions if the result of the load is used multiple times ?
15289  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15290  * - LAST MERGE: 108395.
15291  * - when returning vtypes in registers, generate IR and append it to the end of the
15292  *   last bb instead of doing it in the epilog.
15293  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15294  */
15295
15296 /*
15297
15298 NOTES
15299 -----
15300
15301 - When to decompose opcodes:
15302   - earlier: this makes some optimizations hard to implement, since the low level IR
15303   no longer contains the neccessary information. But it is easier to do.
15304   - later: harder to implement, enables more optimizations.
15305 - Branches inside bblocks:
15306   - created when decomposing complex opcodes. 
15307     - branches to another bblock: harmless, but not tracked by the branch 
15308       optimizations, so need to branch to a label at the start of the bblock.
15309     - branches to inside the same bblock: very problematic, trips up the local
15310       reg allocator. Can be fixed by spitting the current bblock, but that is a
15311       complex operation, since some local vregs can become global vregs etc.
15312 - Local/global vregs:
15313   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15314     local register allocator.
15315   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15316     structure, created by mono_create_var (). Assigned to hregs or the stack by
15317     the global register allocator.
15318 - When to do optimizations like alu->alu_imm:
15319   - earlier -> saves work later on since the IR will be smaller/simpler
15320   - later -> can work on more instructions
15321 - Handling of valuetypes:
15322   - When a vtype is pushed on the stack, a new temporary is created, an 
15323     instruction computing its address (LDADDR) is emitted and pushed on
15324     the stack. Need to optimize cases when the vtype is used immediately as in
15325     argument passing, stloc etc.
15326 - Instead of the to_end stuff in the old JIT, simply call the function handling
15327   the values on the stack before emitting the last instruction of the bb.
15328 */
15329
15330 #else /* !DISABLE_JIT */
15331
15332 MONO_EMPTY_SOURCE_FILE (method_to_ir);
15333
15334 #endif /* !DISABLE_JIT */